1 // license:BSD-3-Clause
2 // copyright-holders:Peter Trauner,Antoine Mine
3 /*****************************************************************************
4 *
5 * saturn.c
6 * portable saturn emulator interface
7 * (hp calculators)
8 *
9 *
10 *****************************************************************************/
11
12 #include "emu.h"
13 #include "saturn.h"
14
15 #include "debugger.h"
16
17
18 //#define VERBOSE 1
19 #include "logmacro.h"
20
21
22 #define R0 0
23 #define R1 1
24 #define R2 2
25 #define R3 3
26 #define R4 4
27 #define A 5
28 #define B 6
29 #define C 7
30 #define D 8
31 #define I 9 // invalid
32
33
34 // Hardware status bits
35 #define XM 1 // external Modules missing
36 #define SB 2 // Sticky bit
37 #define SR 4 // Service Request
38 #define MP 8 // Module Pulled
39
40
41
42 DEFINE_DEVICE_TYPE(SATURN, saturn_device, "saturn_cpu", "Hewlett-Packard Saturn")
43
44
saturn_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)45 saturn_device::saturn_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
46 : cpu_device(mconfig, SATURN, tag, owner, clock)
47 , m_program_config("program", ENDIANNESS_LITTLE, 8, 20, 0)
48 , m_out_func(*this)
49 , m_in_func(*this)
50 , m_reset_func(*this)
51 , m_config_func(*this)
52 , m_unconfig_func(*this)
53 , m_id_func(*this)
54 , m_crc_func(*this)
55 , m_rsi_func(*this)
56 , m_pc(0), m_oldpc(0), m_p(0), m_out(0), m_carry(0), m_decimal(0), m_st(0), m_hst(0)
57 , m_nmi_state(0), m_irq_state(0), m_irq_enable(0), m_in_irq(0), m_pending_irq(0)
58 , m_sleeping(0), m_monitor_id(0), m_monitor_in(0)
59 , m_icount(0)
60 , m_debugger_temp(0)
61 {
62 }
63
memory_space_config() const64 device_memory_interface::space_config_vector saturn_device::memory_space_config() const
65 {
66 return space_config_vector{ std::make_pair(AS_PROGRAM, &m_program_config) };
67 }
68
get_nonstandard_mnemonics_mode() const69 bool saturn_device::get_nonstandard_mnemonics_mode() const
70 {
71 // Needs to become configurable live
72 return false;
73 }
74
75
create_disassembler()76 std::unique_ptr<util::disasm_interface> saturn_device::create_disassembler()
77 {
78 return std::make_unique<saturn_disassembler>(this);
79 }
80
81
82 /***************************************************************
83 * include the opcode macros, functions and tables
84 ***************************************************************/
85
86 #include "satops.ipp"
87 #include "sattable.ipp"
88
89 /*****************************************************************************
90 *
91 * Saturn CPU interface functions
92 *
93 *****************************************************************************/
94
device_start()95 void saturn_device::device_start()
96 {
97 space(AS_PROGRAM).cache(m_cache);
98 space(AS_PROGRAM).specific(m_program);
99
100 m_out_func.resolve_safe();
101 m_in_func.resolve_safe(0);
102 m_reset_func.resolve_safe();
103 m_config_func.resolve_safe();
104 m_unconfig_func.resolve_safe();
105 m_id_func.resolve_safe(0);
106 m_crc_func.resolve_safe();
107 m_rsi_func.resolve_safe();
108
109 memset(m_reg, 0, sizeof(m_reg));
110 memset(m_d, 0, sizeof(m_d));
111 m_pc = 0;
112 m_oldpc = 0;
113 memset(m_rstk, 0, sizeof(m_rstk));
114 m_out = 0;
115 m_carry = 0;
116 m_decimal = 0;
117 m_st = 0;
118 m_hst = 0;
119 m_nmi_state = 0;
120 m_irq_state = 0;
121 m_irq_enable = 0;
122 m_in_irq = 0;
123 m_pending_irq = 0;
124 m_sleeping = 0;
125 m_p = 0;
126
127 save_item(NAME(m_reg[R0]));
128 save_item(NAME(m_reg[R1]));
129 save_item(NAME(m_reg[R2]));
130 save_item(NAME(m_reg[R3]));
131 save_item(NAME(m_reg[R4]));
132 save_item(NAME(m_reg[A]));
133 save_item(NAME(m_reg[B]));
134 save_item(NAME(m_reg[C]));
135 save_item(NAME(m_reg[D]));
136 save_item(NAME(m_d));
137 save_item(NAME(m_pc));
138 save_item(NAME(m_oldpc));
139 save_item(NAME(m_rstk));
140 save_item(NAME(m_out));
141 save_item(NAME(m_carry));
142 save_item(NAME(m_st));
143 save_item(NAME(m_hst));
144 save_item(NAME(m_nmi_state));
145 save_item(NAME(m_irq_state));
146 save_item(NAME(m_irq_enable));
147 save_item(NAME(m_in_irq));
148 save_item(NAME(m_pending_irq));
149 save_item(NAME(m_sleeping));
150
151 // TODO: Register state
152 state_add( SATURN_PC, "PC", m_pc ).formatstr("%5X");
153 state_add( SATURN_D0, "D0", m_d[0] ).formatstr("%5X");
154 state_add( SATURN_D1, "D1", m_d[1] ).formatstr("%5X");
155 state_add( SATURN_A, "A", m_debugger_temp ).formatstr("%19s");
156 state_add( SATURN_B, "B", m_debugger_temp ).formatstr("%19s");
157 state_add( SATURN_C, "C", m_debugger_temp ).formatstr("%19s");
158 state_add( SATURN_D, "D", m_debugger_temp ).formatstr("%19s");
159 state_add( SATURN_R0, "R0", m_debugger_temp ).formatstr("%19s");
160 state_add( SATURN_R1, "R1", m_debugger_temp ).formatstr("%19s");
161 state_add( SATURN_R2, "R2", m_debugger_temp ).formatstr("%19s");
162 state_add( SATURN_R3, "R3", m_debugger_temp ).formatstr("%19s");
163 state_add( SATURN_R4, "R4", m_debugger_temp ).formatstr("%19s");
164 state_add( SATURN_P, "P", m_p).formatstr("%1X");
165 state_add( SATURN_OUT, "OUTP", m_out).formatstr("%3X");
166 state_add( SATURN_CARRY, "Carry", m_carry).formatstr("%1X");
167 state_add( SATURN_ST, "ST", m_st).formatstr("%4X");
168 state_add( SATURN_HST, "HST", m_hst).formatstr("%1X");
169 state_add( SATURN_RSTK0, "RSTK0", m_rstk[0]).formatstr("%5X");
170 state_add( SATURN_RSTK1, "RSTK1", m_rstk[1]).formatstr("%5X");
171 state_add( SATURN_RSTK2, "RSTK2", m_rstk[2]).formatstr("%5X");
172 state_add( SATURN_RSTK3, "RSTK3", m_rstk[3]).formatstr("%5X");
173 state_add( SATURN_RSTK4, "RSTK4", m_rstk[4]).formatstr("%5X");
174 state_add( SATURN_RSTK5, "RSTK5", m_rstk[5]).formatstr("%5X");
175 state_add( SATURN_RSTK6, "RSTK6", m_rstk[6]).formatstr("%5X");
176 state_add( SATURN_RSTK7, "RSTK7", m_rstk[7]).formatstr("%5X");
177 state_add( SATURN_IRQ_STATE, "IRQ", m_debugger_temp).formatstr("%4s");
178 state_add( SATURN_SLEEPING, "sleep", m_sleeping).formatstr("%1X");
179
180 state_add( STATE_GENPC, "GENPC", m_pc ).noshow();
181 state_add( STATE_GENPCBASE, "CURPC", m_pc ).noshow();
182 state_add( STATE_GENFLAGS, "GENFLAGS", m_debugger_temp).formatstr("%2s").noshow();
183
184 set_icountptr(m_icount);
185 }
186
state_string_export(const device_state_entry & entry,std::string & str) const187 void saturn_device::state_string_export(const device_state_entry &entry, std::string &str) const
188 {
189 #define Reg64Data(s) s[15],s[14],s[13],s[12],s[11],s[10],s[9],s[8],s[7],s[6],s[5],s[4],s[3],s[2],s[1],s[0]
190 #define Reg64Format "%x %x%x%x%x%x%x%x %x%x%x %x%x%x%x%x"
191
192 switch (entry.index())
193 {
194 case SATURN_A:
195 str = string_format( Reg64Format, Reg64Data(m_reg[A]) );
196 break;
197
198 case SATURN_B:
199 str = string_format( Reg64Format, Reg64Data(m_reg[B]) );
200 break;
201
202 case SATURN_C:
203 str = string_format( Reg64Format, Reg64Data(m_reg[C]) );
204 break;
205
206 case SATURN_D:
207 str = string_format( Reg64Format, Reg64Data(m_reg[D]) );
208 break;
209
210 case SATURN_R0:
211 str = string_format( Reg64Format, Reg64Data(m_reg[R0]) );
212 break;
213
214 case SATURN_R1:
215 str = string_format( Reg64Format, Reg64Data(m_reg[R1]) );
216 break;
217
218 case SATURN_R2:
219 str = string_format( Reg64Format, Reg64Data(m_reg[R2]) );
220 break;
221
222 case SATURN_R3:
223 str = string_format( Reg64Format, Reg64Data(m_reg[R3]) );
224 break;
225
226 case SATURN_R4:
227 str = string_format( Reg64Format, Reg64Data(m_reg[R4]) );
228 break;
229
230 case SATURN_IRQ_STATE:
231 str = string_format( "%c%c%c%i", m_in_irq?'S':'.', m_irq_enable?'e':'.', m_pending_irq?'p':'.', m_irq_state );
232 break;
233
234 case STATE_GENFLAGS:
235 str = string_format( "%c%c", m_decimal?'D':'.', m_carry ? 'C':'.' );
236 break;
237 }
238 }
239
240
state_import(const device_state_entry & entry)241 void saturn_device::state_import(const device_state_entry &entry)
242 {
243 switch (entry.index())
244 {
245 case SATURN_A:
246 IntReg64(m_reg[A], m_debugger_temp);
247 break;
248
249 case SATURN_B:
250 IntReg64(m_reg[B], m_debugger_temp);
251 break;
252
253 case SATURN_C:
254 IntReg64(m_reg[C], m_debugger_temp);
255 break;
256
257 case SATURN_D:
258 IntReg64(m_reg[D], m_debugger_temp);
259 break;
260
261 case SATURN_R0:
262 IntReg64(m_reg[R0], m_debugger_temp);
263 break;
264
265 case SATURN_R1:
266 IntReg64(m_reg[R1], m_debugger_temp);
267 break;
268
269 case SATURN_R2:
270 IntReg64(m_reg[R2], m_debugger_temp);
271 break;
272
273 case SATURN_R3:
274 IntReg64(m_reg[R3], m_debugger_temp);
275 break;
276
277 case SATURN_R4:
278 IntReg64(m_reg[R4], m_debugger_temp);
279 break;
280 }
281 }
282
state_export(const device_state_entry & entry)283 void saturn_device::state_export(const device_state_entry &entry)
284 {
285 switch (entry.index())
286 {
287 case SATURN_A:
288 m_debugger_temp = Reg64Int(m_reg[A]);
289 break;
290
291 case SATURN_B:
292 m_debugger_temp = Reg64Int(m_reg[B]);
293 break;
294
295 case SATURN_C:
296 m_debugger_temp = Reg64Int(m_reg[C]);
297 break;
298
299 case SATURN_D:
300 m_debugger_temp = Reg64Int(m_reg[D]);
301 break;
302
303 case SATURN_R0:
304 m_debugger_temp = Reg64Int(m_reg[R0]);
305 break;
306
307 case SATURN_R1:
308 m_debugger_temp = Reg64Int(m_reg[R1]);
309 break;
310
311 case SATURN_R2:
312 m_debugger_temp = Reg64Int(m_reg[R2]);
313 break;
314
315 case SATURN_R3:
316 m_debugger_temp = Reg64Int(m_reg[R3]);
317 break;
318
319 case SATURN_R4:
320 m_debugger_temp = Reg64Int(m_reg[R4]);
321 break;
322 }
323 }
324
325
device_reset()326 void saturn_device::device_reset()
327 {
328 m_pc=0;
329 m_sleeping = 0;
330 m_irq_enable = 0;
331 m_in_irq = 0;
332 }
333
334
saturn_take_irq()335 void saturn_device::saturn_take_irq()
336 {
337 m_in_irq = 1; /* reset by software, using RTI */
338 m_pending_irq = 0;
339 m_icount -= 7;
340 saturn_push(m_pc);
341 m_pc=IRQ_ADDRESS;
342
343 LOG("SATURN takes IRQ ($%04x)\n", m_pc);
344
345 standard_irq_callback(SATURN_IRQ_LINE);
346 }
347
execute_run()348 void saturn_device::execute_run()
349 {
350 do
351 {
352 m_oldpc = m_pc;
353
354 debugger_instruction_hook(m_pc);
355
356 if ( m_sleeping )
357 {
358 /* advance time when sleeping */
359 m_icount -= 100;
360 }
361 else
362 {
363 /* takes irq */
364 if ( m_pending_irq && (!m_in_irq) )
365 saturn_take_irq();
366
367 /* execute one instruction */
368 saturn_instruction();
369 }
370
371 } while (m_icount > 0);
372 }
373
374
execute_set_input(int inputnum,int state)375 void saturn_device::execute_set_input(int inputnum, int state)
376 {
377 switch (inputnum)
378 {
379 case SATURN_NMI_LINE:
380 if ( state == m_nmi_state ) return;
381 m_nmi_state = state;
382 if ( state != CLEAR_LINE )
383 {
384 LOG("SATURN set_nmi_line(ASSERT)\n");
385 m_pending_irq = 1;
386 }
387 break;
388
389 case SATURN_IRQ_LINE:
390 if ( state == m_irq_state ) return;
391 m_irq_state = state;
392 if ( state != CLEAR_LINE && m_irq_enable )
393 {
394 LOG("SATURN set_irq_line(ASSERT)\n");
395 m_pending_irq = 1;
396 }
397 break;
398
399 case SATURN_WAKEUP_LINE:
400 if (m_sleeping && state==1)
401 {
402 LOG("SATURN set_wakeup_line(ASSERT)\n");
403 standard_irq_callback(SATURN_WAKEUP_LINE);
404 m_sleeping = 0;
405 }
406 break;
407 }
408 }
409
410
IntReg64(Saturn64 r,int64_t d)411 void saturn_device::IntReg64(Saturn64 r, int64_t d)
412 {
413 int i;
414 for (i=0; i<16; i++)
415 r[i] = (d >> (4*i)) & 0xf;
416 }
417
418
Reg64Int(Saturn64 r)419 int64_t saturn_device::Reg64Int(Saturn64 r)
420 {
421 int64_t x = 0;
422 int i;
423 for (i=0; i<16; i++)
424 x |= (int64_t) r[i] << (4*i);
425 return x;
426 }
427