1 // license:BSD-3-Clause
2 // copyright-holders:Wilbert Pol
3 /*
4 Implementation for Sharp sm8500 cpu. There is hardly any information available
5 on this cpu. Currently we've only found documentation on the microcontroller
6 parts of the cpu, but nothing on the cpu itself.
7
8 Through looking at binary data we have attempted to figure out the opcodes for
9 this cpu, and made educated guesses on the number of cycles for each instruction.
10
11 Code by Wilbert Pol
12
13
14 There is some internal ram for the main cpu registers. They are offset by an index value.
15 The address is (PS0 & 0xF8) + register number. It is not known what happens when PS0 >= F8.
16 The assumption is that F8 to 107 is used, but it might wrap around instead.
17 The registers also mirror out to main RAM, appearing at 0000 to 000F regardless of where
18 they are internally.
19
20 */
21
22 #include "emu.h"
23 #include "sm8500.h"
24 #include "sm8500d.h"
25 #include "debugger.h"
26
27
28 DEFINE_DEVICE_TYPE(SM8500, sm8500_cpu_device, "sm8500", "Sharp SM8500")
29
30
31 static constexpr uint8_t sm8500_b2w[8] = {
32 0, 8, 2, 10, 4, 12, 6, 14
33 };
34
35
sm8500_cpu_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)36 sm8500_cpu_device::sm8500_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
37 : cpu_device(mconfig, SM8500, tag, owner, clock)
38 , m_program_config("program", ENDIANNESS_BIG, 8, 16, 0)
39 , m_dma_func(*this)
40 , m_timer_func(*this)
41 , m_PC(0), m_IE0(0), m_IE1(0), m_IR0(0), m_IR1(0)
42 , m_SYS(0), m_CKC(0), m_clock_changed(0)
43 , m_SP(0)
44 , m_PS0(0)
45 , m_PS1(0), m_IFLAGS(0), m_CheckInterrupts(0), m_halted(0), m_icount(0), m_program(nullptr), m_oldpc(0)
46 {
47 }
48
memory_space_config() const49 device_memory_interface::space_config_vector sm8500_cpu_device::memory_space_config() const
50 {
51 return space_config_vector {
52 std::make_pair(AS_PROGRAM, &m_program_config),
53 };
54 }
55
56
get_sp()57 void sm8500_cpu_device::get_sp()
58 {
59 m_SP = m_program->read_byte(0x1d);
60 if (m_SYS & 0x40) m_SP |= ( m_program->read_byte(0x1c) << 8 );
61 }
62
63
mem_readbyte(uint32_t offset) const64 uint8_t sm8500_cpu_device::mem_readbyte( uint32_t offset ) const
65 {
66 offset &= 0xffff;
67 if ( offset < 0x10)
68 {
69 return m_register_ram[offset + (m_PS0 & 0xF8)];
70 }
71
72 return m_program->read_byte( offset );
73 }
74
75
mem_writebyte(uint32_t offset,uint8_t data)76 void sm8500_cpu_device::mem_writebyte( uint32_t offset, uint8_t data )
77 {
78 uint8_t i;
79 offset &= 0xffff;
80 if (offset < 0x10)
81 {
82 m_register_ram[offset + (m_PS0 & 0xF8)] = data;
83 }
84
85 m_program->write_byte( offset, data );
86
87 switch (offset)
88 {
89 case 0x10: m_IE0 = data; break;
90 case 0x11: m_IE1 = data; break;
91 case 0x12: m_IR0 = data; break;
92 case 0x13: m_IR1 = data; break;
93 case 0x19: m_SYS = data; break;
94 case 0x1a: m_CKC = data; break;
95 case 0x1c:
96 case 0x1d: get_sp(); break;
97 case 0x1e: m_PS0 = data;
98 for (i = 0; i < 16; i++) // refresh register contents in debugger
99 {
100 m_program->write_byte(i, mem_readbyte(i));
101 }
102 break;
103 case 0x1f: m_PS1 = data; break;
104 }
105 }
106
107
device_start()108 void sm8500_cpu_device::device_start()
109 {
110 m_program = &space(AS_PROGRAM);
111
112 m_dma_func.resolve_safe();
113 m_timer_func.resolve_safe();
114
115 save_item(NAME(m_PC));
116 save_item(NAME(m_IE0));
117 save_item(NAME(m_IE1));
118 save_item(NAME(m_IR0));
119 save_item(NAME(m_IR1));
120 save_item(NAME(m_SYS));
121 save_item(NAME(m_CKC));
122 save_item(NAME(m_clock_changed));
123 save_item(NAME(m_SP));
124 save_item(NAME(m_PS0));
125 save_item(NAME(m_PS1));
126 save_item(NAME(m_IFLAGS));
127 save_item(NAME(m_CheckInterrupts));
128 save_item(NAME(m_halted));
129 save_item(NAME(m_oldpc));
130 save_pointer(NAME(m_register_ram),0x108);
131
132 // Register state for debugger
133 state_add(SM8500_PC, "PC", m_PC ).callimport().callexport().formatstr("%04X");
134 state_add(SM8500_SP, "SP", m_SP ).callimport().callexport().formatstr("%04X");
135 state_add(SM8500_PS, "PS", m_PS0 ).callimport().callexport().formatstr("%04s");
136 state_add(SM8500_SYS, "SYS", m_SYS ).callimport().callexport().formatstr("%04X");
137 state_add(SM8500_RR0, "RR0", m_PC ).callimport().callexport().formatstr("%04s");
138 state_add(SM8500_RR2, "RR2", m_PC ).callimport().callexport().formatstr("%04s");
139 state_add(SM8500_RR4, "RR4", m_PC ).callimport().callexport().formatstr("%04s");
140 state_add(SM8500_RR6, "RR6", m_PC ).callimport().callexport().formatstr("%04s");
141 state_add(SM8500_RR8, "RR8", m_PC ).callimport().callexport().formatstr("%04s");
142 state_add(SM8500_RR10, "RR10", m_PC ).callimport().callexport().formatstr("%04s");
143 state_add(SM8500_RR12, "RR12", m_PC ).callimport().callexport().formatstr("%04s");
144 state_add(SM8500_RR14, "RR14", m_PC ).callimport().callexport().formatstr("%04s");
145 state_add(STATE_GENPC, "GENPC", m_PC).formatstr("%8s").noshow();
146 state_add(STATE_GENPCBASE, "CURPC", m_PC).formatstr("%8s").noshow();
147 state_add(STATE_GENFLAGS, "GENFLAGS", m_PS1).formatstr("%8s").noshow();
148
149 set_icountptr(m_icount);
150 }
151
152
state_string_export(const device_state_entry & entry,std::string & str) const153 void sm8500_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) const
154 {
155 switch (entry.index())
156 {
157 case SM8500_PS:
158 str = string_format("%04X", ( m_PS0 << 8 ) | m_PS1 );
159 break;
160
161 case SM8500_RR0:
162 str = string_format("%04X", mem_readword( 0x00 ) );
163 break;
164
165 case SM8500_RR2:
166 str = string_format("%04X", mem_readword( 0x02 ) );
167 break;
168
169 case SM8500_RR4:
170 str = string_format("%04X", mem_readword( 0x04 ) );
171 break;
172
173 case SM8500_RR6:
174 str = string_format("%04X", mem_readword( 0x06 ) );
175 break;
176
177 case SM8500_RR8:
178 str = string_format("%04X", mem_readword( 0x08 ) );
179 break;
180
181 case SM8500_RR10:
182 str = string_format("%04X", mem_readword( 0x0a ) );
183 break;
184
185 case SM8500_RR12:
186 str = string_format("%04X", mem_readword( 0x0c ) );
187 break;
188
189 case SM8500_RR14:
190 str = string_format("%04X", mem_readword( 0x0e ) );
191 break;
192
193 case STATE_GENFLAGS:
194 str = string_format("%c%c%c%c%c%c%c%c",
195 m_PS1 & FLAG_C ? 'C' : '.',
196 m_PS1 & FLAG_Z ? 'Z' : '.',
197 m_PS1 & FLAG_S ? 'S' : '.',
198 m_PS1 & FLAG_V ? 'V' : '.',
199 m_PS1 & FLAG_D ? 'D' : '.',
200 m_PS1 & FLAG_H ? 'H' : '.',
201 m_PS1 & FLAG_B ? 'B' : '.',
202 m_PS1 & FLAG_I ? 'I' : '.' );
203 break;
204 }
205 }
206
207
device_reset()208 void sm8500_cpu_device::device_reset()
209 {
210 for (auto & elem : m_register_ram)
211 {
212 elem = 0;
213 }
214
215 m_PC = 0x1020;
216 m_clock_changed = 0;
217 m_CheckInterrupts = 0;
218 m_halted = 0;
219 m_IFLAGS = 0;
220 mem_writeword(0x10, 0); // IE0, IE1
221 mem_writeword(0x12, 0); // IR0, IR1
222 mem_writeword(0x14, 0xffff); // P0, P1
223 mem_writeword(0x16, 0xff00); // P2, P3
224 mem_writebyte(0x19, 0); // SYS
225 mem_writebyte(0x1a, 0); // CKC
226 mem_writebyte(0x1f, 0); // PS1
227 mem_writebyte(0x2b, 0xff); // URTT
228 mem_writebyte(0x2d, 0x42); // URTS
229 mem_writebyte(0x5f, 0x38); // WDTC
230 }
231
232
233 #define PUSH_BYTE(X) m_SP--; \
234 if ( ( m_SYS & 0x40 ) == 0 ) m_SP &= 0xFF; \
235 mem_writebyte( m_SP, X );
236
237
take_interrupt(uint16_t vector)238 void sm8500_cpu_device::take_interrupt(uint16_t vector)
239 {
240 /* Get regs from ram */
241 get_sp();
242 m_SYS = m_program->read_byte(0x19);
243 m_PS1 = m_program->read_byte(0x1f);
244 /* Push PC */
245 PUSH_BYTE( m_PC & 0xFF );
246 PUSH_BYTE( m_PC >> 8 );
247 /* Push PS1 */
248 PUSH_BYTE( m_PS1 );
249 /* Clear I flag */
250 m_PS1 &= ~ 0x01;
251 /* save regs to ram */
252 m_program->write_byte(0x1f, m_PS1);
253 m_program->write_byte(0x1d, m_SP&0xFF);
254 if (m_SYS&0x40) m_program->write_byte(0x1c, m_SP>>8);
255 /* Change PC to address stored at "vector" */
256 m_PC = mem_readword( vector );
257 }
258
259
process_interrupts()260 void sm8500_cpu_device::process_interrupts()
261 {
262 if ( m_CheckInterrupts )
263 {
264 int irqline = 0;
265 while( irqline < 11 )
266 {
267 if ( m_IFLAGS & ( 1 << irqline ) )
268 {
269 m_halted = 0;
270 m_IE0 = m_program->read_byte(0x10);
271 m_IE1 = m_program->read_byte(0x11);
272 m_IR0 = m_program->read_byte(0x12);
273 m_IR1 = m_program->read_byte(0x13);
274 m_PS0 = m_program->read_byte(0x1e);
275 m_PS1 = m_program->read_byte(0x1f);
276 switch( irqline )
277 {
278 case WDT_INT:
279 take_interrupt( 0x101C );
280 break;
281 case ILL_INT:
282 case NMI_INT:
283 take_interrupt( 0x101E );
284 break;
285 case DMA_INT:
286 m_IR0 |= 0x80;
287 if ( BIT( m_IE0, 7) && BIT( m_PS1, 0) )
288 {
289 take_interrupt( 0x1000 );
290 }
291 break;
292 case TIM0_INT:
293 m_IR0 |= 0x40;
294 if ( BIT( m_IE0, 6) && BIT( m_PS1, 0) )
295 {
296 take_interrupt( 0x1002 );
297 }
298 break;
299 case EXT_INT:
300 m_IR0 |= 0x10;
301 if ( BIT( m_IE0, 4) && ( ( m_PS0 & 0x07 ) < 7 ) && BIT( m_PS1, 0) )
302 {
303 take_interrupt( 0x1006 );
304 }
305 break;
306 case UART_INT:
307 m_IR0 |= 0x08;
308 if ( BIT( m_IE0, 3) && ( ( m_PS0 & 0x07 ) < 6 ) && BIT( m_PS1, 0) )
309 {
310 take_interrupt( 0x1008 );
311 }
312 break;
313 case LCDC_INT:
314 m_IR0 |= 0x01;
315 if ( BIT( m_IE0, 0) && ( ( m_PS0 & 0x07 ) < 5 ) && BIT( m_PS1, 0) )
316 {
317 take_interrupt( 0x100E );
318 }
319 break;
320 case TIM1_INT:
321 m_IR1 |= 0x40;
322 if ( BIT( m_IE1, 6) && ( ( m_PS0 & 0x07 ) < 4 ) && BIT( m_PS1, 0) )
323 {
324 take_interrupt( 0x1012 );
325 }
326 break;
327 case CK_INT:
328 m_IR1 |= 0x10;
329 if ( BIT( m_IE1, 4) && ( ( m_PS0 & 0x07 ) < 3 ) && BIT( m_PS1, 0) )
330 {
331 take_interrupt( 0x1016 );
332 }
333 break;
334 case PIO_INT:
335 m_IR1 |= 0x04;
336 if ( BIT( m_IE1, 2) && ( ( m_PS0 & 0x07 ) < 2 ) && BIT( m_PS1, 0) )
337 {
338 take_interrupt( 0x101A );
339 }
340 break;
341 }
342 m_IFLAGS &= ~ ( 1 << irqline );
343 m_program->write_byte(0x12, m_IR0);
344 m_program->write_byte(0x13, m_IR1);
345 }
346 irqline++;
347 }
348 }
349 }
350
351
create_disassembler()352 std::unique_ptr<util::disasm_interface> sm8500_cpu_device::create_disassembler()
353 {
354 return std::make_unique<sm8500_disassembler>();
355 }
356
357
execute_run()358 void sm8500_cpu_device::execute_run()
359 {
360 do
361 {
362 int mycycles = 0;
363 uint8_t r1,r2;
364 uint16_t s1,s2;
365 uint32_t d1,d2;
366 uint32_t res;
367
368 debugger_instruction_hook(m_PC);
369 m_oldpc = m_PC;
370 process_interrupts();
371 if ( !m_halted ) {
372 uint8_t op = mem_readbyte( m_PC++ );
373 m_SYS = m_program->read_byte(0x19);
374 m_PS0 = m_program->read_byte(0x1e);
375 m_PS1 = m_program->read_byte(0x1f);
376 get_sp();
377 switch( op )
378 {
379 #include "sm85ops.h"
380 }
381 if (m_SYS&0x40) m_program->write_byte(0x1c,m_SP>>8);
382 m_program->write_byte(0x1d,m_SP&0xFF);
383 mem_writebyte(0x1e,m_PS0); // need to update debugger
384 m_program->write_byte(0x1f,m_PS1);
385 } else {
386 mycycles = 4;
387 m_dma_func( mycycles );
388 }
389 m_timer_func( mycycles );
390 m_icount -= mycycles;
391 } while ( m_icount > 0 );
392 }
393
394
execute_set_input(int inptnum,int state)395 void sm8500_cpu_device::execute_set_input( int inptnum, int state )
396 {
397 m_IR0 = m_program->read_byte(0x12);
398 m_IR1 = m_program->read_byte(0x13);
399 if ( state == ASSERT_LINE )
400 {
401 m_IFLAGS |= ( 0x01 << inptnum );
402 m_CheckInterrupts = 1;
403 switch( inptnum )
404 {
405 case DMA_INT: m_IR0 |= 0x80; break;
406 case TIM0_INT: m_IR0 |= 0x40; break;
407 case EXT_INT: m_IR0 |= 0x10; break;
408 case UART_INT: m_IR0 |= 0x08; break;
409 case LCDC_INT: m_IR0 |= 0x01; break;
410 case TIM1_INT: m_IR1 |= 0x40; break;
411 case CK_INT: m_IR1 |= 0x10; break;
412 case PIO_INT: m_IR1 |= 0x04; break;
413 }
414 }
415 else
416 {
417 m_IFLAGS &= ~( 0x01 << inptnum );
418 switch( inptnum )
419 {
420 case DMA_INT: m_IR0 &= ~0x80; break;
421 case TIM0_INT: m_IR0 &= ~0x40; break;
422 case EXT_INT: m_IR0 &= ~0x10; break;
423 case UART_INT: m_IR0 &= ~0x08; break;
424 case LCDC_INT: m_IR0 &= ~0x01; break;
425 case TIM1_INT: m_IR1 &= ~0x40; break;
426 case CK_INT: m_IR1 &= ~0x10; break;
427 case PIO_INT: m_IR1 &= ~0x04; break;
428 }
429 if ( 0 == m_IFLAGS )
430 {
431 m_CheckInterrupts = 0;
432 }
433 }
434 m_program->write_byte(0x12, m_IR0);
435 m_program->write_byte(0x13, m_IR1);
436 }
437