aboutsummaryrefslogtreecommitdiff
path: root/SrcShared/EmSession.h
blob: a514ad6534699d211c727c1197d92235e6c9e89b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
/* -*- mode: C++; tab-width: 4 -*- */
/* ===================================================================== *\
	Copyright (c) 2000-2001 Palm, Inc. or its subsidiaries.
	All rights reserved.

	This file is part of the Palm OS Emulator.

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.
\* ===================================================================== */

#ifndef EmSession_h
#define EmSession_h

#include "EmDevice.h"			// EmDevice
#include "EmDlg.h"				// EmDlgItemID, EmCommonDialogFlags
#include "EmThreadSafeQueue.h"	// EmThreadSafeQueue
#include "Skins.h"				// SkinElementType

#if HAS_OMNI_THREAD
#include "omnithread.h" 		// omni_thread, omni_mutex, omni_condition
#endif

/*
**	EmSession is the class used to manage an emulation session.  Its
**	responsibilities are:
**	
**		* Create new session
**		* Save session to disk
**		* Load old session from disk or resources
**		* Manage the "CPU loop"
**		* Synchronize with running session
**		* Destroy session
**
**	That's the main abstraction.  However, as you can tell from the
**	interface, a number of other duties have crept in, including:
**	
**		* UI interaction
**		* Gremlins coordination
**		* Instruction and data breakpoints
*/


// ---------------------------------------------------------------------------
#pragma mark EmSuspendCounters
// ---------------------------------------------------------------------------

/*
**	The CPU loop can be suspended for any number of reasons by any number of
**	sources.  EmSuspendCounters records which clients have requested that
**	the CPU loop be suspended and for what reason.  To support nesting, it
**	keeps track of those statistics as counters instead of booleans.  If
**	it's OK by any client for the CPU loop to run, its counter is zero. 
**	Otherwise, it gets incremented to non-zero.  When the CPU loop checks to
**	see if it's OK to run, it looks at all of these counters en masse via
**	the union nature of EmSuspendState.
*/

struct EmSuspendCounters
{
	// Incremented by calls to EmSession::SuspendThread.  Decremented on
	// calls to EmSession::ResumeThread.  For executing commands, getting
	// LCD data, etc.

	int	fSuspendByUIThread			: 4;

	// Incremented when an exception or error occurs.  Decremented (or
	// cleared) when the debugger sends a Continue packet.

	int	fSuspendByDebugger			: 4;

	// Incremented on calls to HostSessionSuspend, or an implicit
	// scripting suspend occurred.  Decremented on HostSessionResume.

	int	fSuspendByExternal			: 4;

	// Set when it's time for the CPU thread to exit after running for a
	// little while.  Used on the Mac, and on other systems when calling
	// a Palm OS function that needs to occasionally return control (as
	// when installing a file with the Exchange Manager).

	int	fSuspendByTimeout			: 1;

	// Set when we're leaving because we called Execute in order to spin
	// the state up to a system call, and that state is reached.

	int	fSuspendBySysCall			: 1;

	// Set when we're leaving because we called Execute in order to call
	// a subroutine, and that subroutine returned.

	int	fSuspendBySubroutineReturn	: 1;
};


// ---------------------------------------------------------------------------
#pragma mark EmSuspendState
// ---------------------------------------------------------------------------

/*
**	EmSuspendState is a union of EmSuspendCounters and a 32-bit integer.  Its
**	purpose is to allow the testing of *all* the suspend flags at once.  If
**	any flag is set, then emulation is suspended.
*/

union EmSuspendState
{
	EmSuspendCounters	fCounters;
	uint32				fAllCounters;
};


// ---------------------------------------------------------------------------
#pragma mark EmSessionState
// ---------------------------------------------------------------------------

/*
**	The current state of the "CPU loop".  If the stateis kSuspended, the
**	reason for that suspension can usually be found in EmSuspendState.
*/

enum EmSessionState
{
	kRunning,		// The CPU thread is running.
	kStopped,		// The CPU thread is not started or has finished.
	kSuspended,		// The CPU thread is suspended at the end of a cycle.
	kBlockedOnUI	// The CPU thread is waiting for a dialog to be handled.
};


// ---------------------------------------------------------------------------
#pragma mark EmStopMethod
// ---------------------------------------------------------------------------

/*
**	An enumerated value passed to EmSessionStopper (or SuspendThread if it's
**	called directly) describing the way in which the thread should be
**	suspended.
*/

enum EmStopMethod
{
	kStopNone,		// Don't stop the CPU.

	kStopNow,		// Suspend now, no matter what.

	kStopOnCycle,	// Suspend at the end of a cycle.  This request may
					// fail if the CPU thread is blocked on the UI.

	kStopOnSysCall	// Suspend on the next call to a system function.  This
					// request may fail if the CPU thread is block on the
					// UI.  The request may *hang* if the CPU thread is in
					// a state such that it never reaches a system call.
};


// ---------------------------------------------------------------------------
#pragma mark EmButtonEvent
// ---------------------------------------------------------------------------

/*
**	Struct containing all data for a button event (that is, when the user
**	clicks the mouse on a hard button, or presses an FKEY bound to one of
**	the hard buttons).
*/

struct EmButtonEvent
{
	EmButtonEvent (SkinElementType button, Bool isDown) :
		fButton (button),
		fButtonIsDown (isDown)
	{
	}

	SkinElementType	fButton;
	Bool			fButtonIsDown;
};

typedef EmThreadSafeQueue<EmButtonEvent>	EmButtonQueue;


// ---------------------------------------------------------------------------
#pragma mark EmKeyEvent
// ---------------------------------------------------------------------------

/*
**	Struct containing all data for a key event.
*/

struct EmKeyEvent
{
	EmKeyEvent (uint16 ch) :
		fKey (ch),
		fShiftDown (0),
		fCapsLockDown (0),
		fNumLockDown (0),
		fCommandDown (0),
		fOptionDown (0),
		fControlDown (0),
		fAltDown (0),
		fWindowsDown (0)
		{}

	uint16	fKey;
	Bool	fShiftDown;
	Bool	fCapsLockDown;
	Bool	fNumLockDown;
	Bool	fCommandDown;
	Bool	fOptionDown;
	Bool	fControlDown;
	Bool	fAltDown;
	Bool	fWindowsDown;
};

typedef EmThreadSafeQueue<EmKeyEvent>	EmKeyQueue;


// ---------------------------------------------------------------------------
#pragma mark EmPenEvent
// ---------------------------------------------------------------------------

/*
**	Struct containing all data for a pen event (that is, when the user clicks
**	the mouse in the touchscreen area).
*/

struct EmPenEvent
{
	EmPenEvent (const EmPoint& point, Bool isDown) :
		fPenPoint (point),
		fPenIsDown (isDown)
	{
	}

	EmPoint	fPenPoint;
	Bool	fPenIsDown;

	bool operator==(const EmPenEvent& other) const
	{
		return fPenPoint == other.fPenPoint &&
			fPenIsDown == other.fPenIsDown;
	}
};

typedef EmThreadSafeQueue<EmPenEvent>	EmPenQueue;


// ---------------------------------------------------------------------------
#pragma mark Instruction/DataBreak
// ---------------------------------------------------------------------------

/*
**	Data types and collections for managing functions that install, remove,
**	and respond to instruction and data breaks.
**
**	Instruction breaks occur when the PC reaches an indicated memory location.
**	Data breaks occur when an indicated memory location is accessed (either
**	read or write).  An instruction or instruction data fetch does not trigger
**	a data break.  (!!! Actually, I think the latter does...should it?)
*/

typedef void	(*InstructionBreakInstaller)	(void);
typedef void	(*InstructionBreakRemover)		(void);
typedef void	(*InstructionBreakReacher)		(void);

struct InstructionBreakFuncs
{
	InstructionBreakInstaller	fInstaller;
	InstructionBreakRemover		fRemover;
	InstructionBreakReacher		fReacher;
};

typedef vector<InstructionBreakFuncs>	InstructionBreakFuncList;


typedef void	(*DataBreakInstaller)	(void);
typedef void	(*DataBreakRemover)		(void);
typedef void	(*DataBreakReacher)		(emuptr, int size, Bool forRead);

struct DataBreakFuncs
{
	DataBreakInstaller			fInstaller;
	DataBreakRemover			fRemover;
	DataBreakReacher			fReacher;
};

typedef vector<DataBreakFuncs>	DataBreakFuncList;


// ---------------------------------------------------------------------------
#pragma mark EmSession
// ---------------------------------------------------------------------------

class EmCPU;
class EmDeferredErr;
class SessionFile;
struct Configuration;

typedef vector<EmDeferredErr*>	EmDeferredErrList;

class EmSession;
extern EmSession*	gSession;

class EmSession
{
	public:
		// -----------------------------------------------------------------------------
		// constructor / destructor
		// -----------------------------------------------------------------------------

								EmSession 			(void);
				 				~EmSession			(void);

		// -----------------------------------------------------------------------------
		// public methods
		// -----------------------------------------------------------------------------

		// Methods to create a new session.  One of these methods must be called after
		// creation the EmSession object.  CreateNew creates a new session based on
		// the data in Configuration.  CreateOld reads a previously saved session from
		// the given file.  CreateBound reads a previously saved session from resources
		// bound to the file.
		//
		// After a session has been created, the client needs to call CreateThread.
		// If "true" is passed to CreateThread, the client also needs to call
		// ResumeThread.  (On the Mac, it only makes sense to pass "false".)

		void					CreateNew			(const Configuration&);
		void					CreateOld			(const EmFileRef&);
		void					CreateBound			(void);

		// Standard sub-system methods:
		//		Reset:	Resets the state.  Called on hardware resets or on
		//				calls to SysReset.  Also called from constructor.
		//		Save:	Saves the state to the given file.
		//		Load:	Loads the state from the given file.  Can assume that
		//				Reset has been called first.

		void 					Reset				(EmResetType);
		void 					Save				(SessionFile&);
		void 					Load				(SessionFile&);

		// Utility methods that create a SessionFile for the given file, and then
		// call the above Save and Load methods.  If updateFileRef is true, then
		// the EmFileRef is remembered as part of the session's "identity".

		void 					Save				(const EmFileRef&,
													 Bool updateFileRef);
		void 					Load				(const EmFileRef&);

		// Called by external thread to create and destroy the thread.  CreateThread
		// is called after the EmSession is created.  If "suspended" is true, the
		// client should also call ResumeThread.  If "suspended" is false, the
		// thread will start running immediately.  DestroyThread can be called
		// manually, but will also be called in the destructor (getting called
		// more than once is OK).

		void					CreateThread		(Bool suspended);
		void					DestroyThread		(void);

		// Called by external thread to suspend and resume the CPU thread.  Not
		// normally called directly by clients.  Instead, clients should use
		// a stack-based EmSessionStopper object.

		Bool					SuspendThread		(EmStopMethod how);
		void					ResumeThread		(void);

#if HAS_OMNI_THREAD
		// Pause the thread by the given number of milliseconds.

		void					Sleep				(unsigned long msecs);

		// Return whether or not the calling function is executing in the context of
		// the CPU thread or not.  If not, it's most likely executing in the UI
		// thread -- much of Poser assumes this is the case.
		//
		// It's not clear if this function should return true or false on single-
		// threaded systems, so it's not available to those.

		Bool					InCPUThread			(void) const;
#endif

		// GetSessionState returns the state of the CPU thread, as described in the
		// definition of the EmSessionState type.  If the thread is suspended, you
		// can call GetSuspendState to find out why.  After a thread has been
		// suspended, you might need to clear the reason for it being suspended
		// by calling SetSuspendState before calling ResumeThread.
		//
		// These methods are protected by their own mutex, and can be called
		// by any thread.

		EmSessionState			GetSessionState		(void) const;
		EmSuspendState			GetSuspendState		(void) const;
		void					SetSuspendState		(const EmSuspendState&);

		// Called on the Mac at idle time to execute a little bit then leave.
		// Also called by SuspendThread when the CPU state needs to be halted
		// on a system call or when the Palm OS is idle.
		//
		// Clients should check the suspend state in order to make sure that
		// ExecuteIncremental exitted for the right reason.  If the reason was
		// fSuspendByTimeout, this flag will automatically be cleared before
		// the function returns.  If the reason was fSuspendByDebugger, then
		// the debugger will have already been contacted.
		//
		// If the suspend state is non-zero when this function is called, the
		// function merely exits immediately.

		void					ExecuteIncremental	(void);

		// Called by mechanisms that allow the calling of Palm OS system functions
		// as if they were Poser subroutines.
		//
		// Clients should check the suspend state in order to make sure that
		// ExecuteSubroutine exitted for the right reason.
		//
		// If the suspend state is non-zero when this function is called, the
		// function saves that state, clears the suspend flags, and then enters
		// the CPU loop.  The previous suspend state flags are restored on
		// exit.  If any benign suspend flags were set while executing the
		// Palm OS subroutine (for instance, fSuspendByTimeout), those flags
		// are applied to the previously-saved flags before they are restored.

		void					ExecuteSubroutine	(void);

		// Called by the CPU thread if any processor-independent "end of cycle"
		// processing needs to be carried out (for instance, Gremlins needs to
		// save a snapshot or needs to switch to a previously saved state).
		//
		// This method is also responsible for resetting the emulation state
		// (either in response to a hardware reset or a call to SysReset).
		// "checkForResetOnly" is true if *only* this responsibility should
		// be carried out and any other duties should be skipped.  If it's
		// false, then all end-of-cycle duties should be carried out.

		Bool					ExecuteSpecial		(Bool checkForResetOnly);

		Bool					CheckForBreak		(void);

		// Called by the CPU thread when it needs to display an error message.
		// Do NOT call this from any other thread.

		EmDlgItemID				BlockOnDialog		(EmDlgThreadFn fn,
													 const void* parameters);

#if HAS_OMNI_THREAD
		// Called by the UI thread when the dialog has been dismissed, or
		// if a thread blocked on the UI needs to be stopped.  In the
		// former case, dialogResult should be set to the button that
		// dismissed the dialog.  In the latter case, dialogResult should
		// be set to -1.

		void					UnblockDialog		(void);
#endif

		// Methods for interacting with the UI:
		//
		//	PostFooEvent:
		//		Called by the UI thread to post UI events.  Clients need not
		//		synchronize with the CPU thread first.  These methods will do
		//		whatever is needed.
		//
		//	HasFooEvent:
		//		Returns true if there's an event posted to the queue.
		//
		//	PeekFooEvent:
		//		Returns the top event on the queue, but doesn't remove it
		//		from the queue.
		//
		//	GetFooEvent:
		//		Returns the top event from the queue and removes it from
		//		the queue.
		//
		// These methods are protected by their own mutex, and can be called
		// by any thread.

		void					PostButtonEvent		(const EmButtonEvent&, Bool postNow = false);
		Bool					HasButtonEvent		(void);
		EmButtonEvent			PeekButtonEvent		(void);
		EmButtonEvent			GetButtonEvent		(void);

		void					PostKeyEvent		(const EmKeyEvent&);
		Bool					HasKeyEvent			(void);
		EmKeyEvent				PeekKeyEvent		(void);
		EmKeyEvent				GetKeyEvent			(void);

		void					PostPenEvent		(const EmPenEvent&);
		Bool					HasPenEvent			(void);
		EmPenEvent				PeekPenEvent		(void);
		EmPenEvent				GetPenEvent			(void);

		void					ReleaseBootKeys		(void);

		// Method for getting information on the device we're emulating.
		// Callable at any time from any thread.

		Configuration			GetConfiguration	(void);
		EmFileRef				GetFile				(void);
		EmDevice				GetDevice			(void);

		// Methods for determining if emulation should halt at certain
		// points.  Called inside the CPU thread.

		Bool					GetBreakOnSysCall	(void);

		// Called by the CPU thread to determine if emulation code is being
		// executed as part of normal emulation, or as part of a subroutine
		// call into the Palm OS.  Certain features may be enable or disabled
		// as a result of this check (for instance, breakpoints are generally
		// disabled when Poser is making a Palm OS subroutine call).

		Bool					IsNested			(void);

		// Methods for determining if post-load operations need to take
		// place.  Called inside the CPU thread.

		Bool					GetNeedPostLoad		(void);
		void					SetNeedPostLoad		(Bool);

		// Schedule for the CPU thread to suspend.  Called inside the CPU thread.

		void					ScheduleSuspendException			(void);
		void					ScheduleSuspendError				(void);
		void					ScheduleSuspendExternal				(void);
		void					ScheduleSuspendTimeout				(void);
		void					ScheduleSuspendSysCall				(void);
		void					ScheduleSuspendSubroutineReturn		(void);

		void					ScheduleResumeExternal				(void);

		// Schedule for stuff to happen at the end of the current instruction
		// cycle.  Called inside the CPU thread.

		void					ScheduleReset							(EmResetType);
		void					ScheduleResetBanks						(void);
		void					ScheduleAutoSaveState					(void);
		void					ScheduleSaveRootState					(void);
		void					ScheduleSaveSuspendedState				(void);
		void					ScheduleLoadRootState					(void);
		void					ScheduleNextGremlinFromRootState		(void);
		void					ScheduleNextGremlinFromSuspendedState	(void);
		void					ScheduleMinimizeLoadState			(void);
		void					ScheduleDeferredError					(EmDeferredErr*);

		void					ClearDeferredErrors						(void);

		// Provide routines that get called when it's appropriate to install an
		// instruction break, when it's appropriate to remove an instruction break,
		// or when an instruction break has been reached.  Called by various
		// sub-systems in their Initialize methods.

		void					AddInstructionBreakHandlers	(InstructionBreakInstaller,
															 InstructionBreakRemover,
															 InstructionBreakReacher);

		// Provide routines that get called when it's appropriate to install a
		// data break, when it's appropriate to remove a data break, or when a
		// data break has been reached.  Called by various sub-systems in their
		// Initialize methods.

		void					AddDataBreakHandlers		(DataBreakInstaller,
															 DataBreakRemover,
															 DataBreakReacher);

		// Call the installed routines to install/remove the breakpoints.

		void					InstallInstructionBreaks	(void);
		void					RemoveInstructionBreaks		(void);
		void					HandleInstructionBreak		(void);

		void					InstallDataBreaks			(void);
		void					RemoveDataBreaks			(void);
		void					HandleDataBreak				(emuptr, int size, Bool forRead);

	private:
		// Initialize the state of the session and all of it's sub-systems based
		// on the given configuration.  The configuration is also saved and can
		// later be queried if needed.

		void					Initialize					(const Configuration&);

		// Dispose of all of our resources, as well as all of our sub-systems'.
		// Called from the destructor (after first stopping the CPU thread).

		void					Dispose						(void);

#if HAS_OMNI_THREAD
		// -----------------------------------------------------------------------------
		// omni_thread overrides
		// -----------------------------------------------------------------------------

		static void				RunStatic			(void* arg);
		void					Run					(void);
#endif

		void					CallCPU				(void);

	private:
		friend class EmCPU;
		friend class EmCPU68K;	// Accesses fSuspendState and fStop directly.

	private:
		Configuration			fConfiguration;
		EmFileRef				fFile;

		EmCPU*					fCPU;

#if HAS_OMNI_THREAD
		// Accessed from external thread only.

		omni_thread*			fThread;

		// Accessed from any thread.

		mutable omni_mutex		fSharedLock;
		mutable omni_condition	fSharedCondition;

		omni_mutex				fSleepLock;
		omni_condition			fSleepCondition;
#endif

		// ----------------------------------------------------------------------
		// The variables in this section are protected by the mutex, and should
		// not be accessed without first acquiring it.
		// ----------------------------------------------------------------------

#if HAS_OMNI_THREAD
		// Set to true if the thread should quit.  If set by an external
		// thread, the CPU thread will notice the request, but not immediately.
		// If set internally, the CPU thread should also set SPCFLAG_EXIT of
		// regs.spcflags in order for it to get noticed.

		Bool					fStop;
#endif

		// Set to non-zero if the thread should pause.  If set by an external
		// thread, the CPU thread will notice the request, but not immediately.
		// If set internally, the CPU thread should also set SPCFLAG_SUSPEND of
		// regs.spcflags in order for it to get noticed.

		EmSuspendState			fSuspendState;

		// Set to kStopped when the thread is about to quit.
		//
		// Set to kSuspended when the thread is about to suspend.
		//
		// Set to kBlockedOnUI when thread is waiting for UI thread
		// to display a dialog.  UI thread should set this
		// to false after the dialog is displayed and dismissed.
		//
		// Otherwise, set to kRunning.

		EmSessionState			fState;

		// These values are read in any thread at any time, but should only
		// be changed after stopping the CPU thread.  They're set up by the
		// ExecuteUntilFoo methods.

		Bool					fBreakOnSysCall;
		int						fNestLevel;

		Bool					fNeedPostLoad;

		// These values indicate that certain end-of-cycle actions
		// should take place.

		Bool					fReset;
		Bool					fResetBanks;
		Bool					fHordeAutoSaveState;
		Bool					fHordeSaveRootState;
		Bool					fHordeSaveSuspendState;
		Bool					fHordeLoadRootState;
		Bool					fHordeNextGremlinFromRootState;
		Bool					fHordeNextGremlinFromSuspendState;
		Bool					fMinimizeLoadState;

		EmDeferredErrList		fDeferredErrs;

		EmResetType				fResetType;

	private:
		EmButtonQueue			fButtonQueue;
		EmKeyQueue				fKeyQueue;
		EmPenQueue				fPenQueue;

		EmPenEvent				fLastPenEvent;
		uint32					fBootKeys;

	private:
		InstructionBreakFuncList	fInstructionBreakFuncs;
		DataBreakFuncList			fDataBreakFuncs;
};


// ---------------------------------------------------------------------------
#pragma mark EmSessionStopper
// ---------------------------------------------------------------------------

/*
**	Stack object used to briefly stop the emulator.
*/

class EmSessionStopper
{
	public:
								EmSessionStopper	(EmSession*, EmStopMethod how);
								~EmSessionStopper 	(void);

		Bool					Stopped				(void);
		Bool					CanCall				(void);

	private:
		EmSession*				fSession;
		int						fHow;
		Bool					fStopped;
};


// Inlined because it's called from EmCPU68K::Execute on every opcode.

inline Bool EmSession::IsNested (void)
{
	return fNestLevel > 0;
}

#endif /* EmSession_h */