Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/lynx/system.cpp
2 views
1
//
2
// Copyright (c) 2004 K. Wilkins
3
//
4
// This software is provided 'as-is', without any express or implied warranty.
5
// In no event will the authors be held liable for any damages arising from
6
// the use of this software.
7
//
8
// Permission is granted to anyone to use this software for any purpose,
9
// including commercial applications, and to alter it and redistribute it
10
// freely, subject to the following restrictions:
11
//
12
// 1. The origin of this software must not be misrepresented; you must not
13
// claim that you wrote the original software. If you use this software
14
// in a product, an acknowledgment in the product documentation would be
15
// appreciated but is not required.
16
//
17
// 2. Altered source versions must be plainly marked as such, and must not
18
// be misrepresented as being the original software.
19
//
20
// 3. This notice may not be removed or altered from any source distribution.
21
//
22
23
//////////////////////////////////////////////////////////////////////////////
24
// Handy - An Atari Lynx Emulator //
25
// Copyright (c) 1996,1997 //
26
// K. Wilkins //
27
//////////////////////////////////////////////////////////////////////////////
28
// System object class //
29
//////////////////////////////////////////////////////////////////////////////
30
// //
31
// This class provides the glue to bind of of the emulation objects //
32
// together via peek/poke handlers and pass thru interfaces to lower //
33
// objects, all control of the emulator is done via this class. Update() //
34
// does most of the work and each call emulates one CPU instruction and //
35
// updates all of the relevant hardware if required. It must be remembered //
36
// that if that instruction involves setting SPRGO then, it will cause a //
37
// sprite painting operation and then a corresponding update of all of the //
38
// hardware which will usually involve recursive calls to Update, see //
39
// Mikey SPRGO code for more details. //
40
// //
41
// K. Wilkins //
42
// August 1997 //
43
// //
44
//////////////////////////////////////////////////////////////////////////////
45
// Revision History: //
46
// ----------------- //
47
// //
48
// 01Aug1997 KW Document header added & class documented. //
49
// //
50
//////////////////////////////////////////////////////////////////////////////
51
52
#define SYSTEM_CPP
53
54
//#include <crtdbg.h>
55
//#define TRACE_SYSTEM
56
57
#include "system.h"
58
59
CSystem::CSystem(const uint8 *game, uint32 gamesize, const uint8 *bios, uint32 biossize, int pagesize0, int pagesize1, bool lowpass)
60
{
61
// load lynxboot.img
62
mRom = new CRom(bios, biossize);
63
64
mCart = new CCart(game, gamesize, pagesize0, pagesize1);
65
mRam = new CRam();
66
67
mMikie = new CMikie(*this);
68
mSusie = new CSusie(*this);
69
70
// Instantiate the memory map handler
71
mMemMap = new CMemMap(*this);
72
73
// Now the handlers are set we can instantiate the CPU as is will use handlers on reset
74
mCpu = new C65C02(*this);
75
76
mMikie->mikbuf.set_sample_rate(44100, 60);
77
mMikie->mikbuf.clock_rate((long int)(16000000 / 4));
78
mMikie->mikbuf.bass_freq(60);
79
mMikie->miksynth.volume(0.50);
80
mMikie->miksynth.treble_eq(lowpass ? -35 : 0);
81
82
// Now init is complete do a reset, this will cause many things to be reset twice
83
Reset();
84
}
85
86
CSystem::~CSystem()
87
{
88
delete mCart;
89
delete mRom;
90
delete mRam;
91
delete mCpu;
92
delete mMikie;
93
delete mSusie;
94
delete mMemMap;
95
}
96
97
void CSystem::Reset()
98
{
99
gSystemCycleCount=0;
100
gNextTimerEvent=0;
101
// gCPUBootAddress=0;
102
gSystemIRQ=FALSE;
103
gSystemNMI=FALSE;
104
gSystemCPUSleep=FALSE;
105
gSystemHalt=FALSE;
106
gSuzieDoneTime = 0;
107
108
mMemMap->Reset();
109
mCart->Reset();
110
mRom->Reset();
111
mRam->Reset();
112
mMikie->Reset();
113
mSusie->Reset();
114
mCpu->Reset();
115
}
116
117
/*
118
static int Load(MDFNFILE *fp)
119
{
120
try
121
{
122
lynxie = new CSystem(fp->data, fp->size);
123
124
switch(lynxie->CartGetRotate())
125
{
126
case CART_ROTATE_LEFT:
127
MDFNGameInfo->rotated = MDFN_ROTATE270;
128
break;
129
130
case CART_ROTATE_RIGHT:
131
MDFNGameInfo->rotated = MDFN_ROTATE90;
132
break;
133
}
134
135
memcpy(MDFNGameInfo->MD5, lynxie->mCart->MD5, 16);
136
MDFNGameInfo->GameSetMD5Valid = FALSE;
137
138
MDFN_printf(_("ROM: %dKiB\n"), (lynxie->mCart->InfoROMSize + 1023) / 1024);
139
MDFN_printf(_("ROM CRC32: 0x%08x\n"), lynxie->mCart->CRC32());
140
MDFN_printf(_("ROM MD5: 0x%s\n"), md5_context::asciistr(MDFNGameInfo->MD5, 0).c_str());
141
142
MDFNGameInfo->fps = (uint32)(59.8 * 65536 * 256);
143
144
if(MDFN_GetSettingB("lynx.lowpass"))
145
{
146
lynxie->mMikie->miksynth.treble_eq(-35);
147
}
148
else
149
{
150
lynxie->mMikie->miksynth.treble_eq(0);
151
}
152
153
}
154
*/
155
156
bool CSystem::Advance(int buttons, uint32 *vbuff, int16 *sbuff, int &sbuffsize)
157
{
158
// this check needs to occur at least once every 250 million cycles or better
159
mMikie->CheckWrap();
160
161
SetButtonData(buttons);
162
mSusie->lagged = true;
163
164
uint32 start = gSystemCycleCount;
165
166
// nominal timer values are div16 for prescalar, 158 for line timer, and 104 for frame timer
167
// reloads are actually +1 due to the way the hardware works
168
// so this is a frame, theoretically
169
uint32 target = gSystemCycleCount + 16 * 105 * 159 - frameoverflow;
170
171
// audio start frame
172
mMikie->startTS = start;
173
174
videobuffer = vbuff;
175
176
while (gSystemCycleCount < target)
177
//while (mMikie->mpDisplayCurrent && gSystemCycleCount - start < 800000)
178
{
179
Update(target);
180
}
181
182
// total cycles executed is now gSystemCycleCount - start
183
frameoverflow = gSystemCycleCount - target;
184
185
mMikie->mikbuf.end_frame((gSystemCycleCount - start) >> 2);
186
sbuffsize = mMikie->mikbuf.read_samples(sbuff, sbuffsize);
187
188
return mSusie->lagged;
189
}
190
191
void CSystem::Blit(const uint32 *src)
192
{
193
if (!videobuffer)
194
{
195
// a game shouldn't be able to get two frames in in the length of time we traverse in a single
196
// call to advance. what is going on here?
197
return;
198
}
199
200
const int W = 160;
201
const int H = 102;
202
203
switch (rotate)
204
{
205
case 0:
206
std::memcpy(videobuffer, src, sizeof(uint32) * W * H);
207
break;
208
case 1:
209
{
210
uint32 *dest = videobuffer + H * (W - 1);
211
for (int j = 0; j < H; j++)
212
{
213
for (int i = 0; i < W; i++)
214
{
215
*dest = *src++;
216
dest -= H;
217
}
218
dest += H * W + 1;
219
}
220
}
221
break;
222
case 2:
223
{
224
uint32 *dest = videobuffer + H * W - 1;
225
for (int i = 0; i < W * H; i++)
226
{
227
*dest-- = *src++;
228
}
229
}
230
break;
231
case 3:
232
{
233
uint32 *dest = videobuffer + H - 1;
234
for (int j = 0; j < H; j++)
235
{
236
for (int i = 0; i < W; i++)
237
{
238
*dest = *src++;
239
dest += H;
240
}
241
dest -= H * W + 1;
242
}
243
}
244
break;
245
}
246
247
videobuffer = nullptr;
248
}
249
250
void CSystem::SetButtonData(uint32 data)
251
{
252
// bit: 7654
253
// input DURL
254
// rot=1 RLUD
255
// rot=2 UDLR
256
// rot=3 LRDU
257
258
uint32 newdata;
259
switch (rotate)
260
{
261
case 0:
262
newdata = data; break;
263
case 1:
264
newdata = data & 0xff0f | data >> 3 & 0x0010 | data >> 1 & 0x0020 | data << 2 & 0x00c0; break;
265
case 2:
266
newdata = data & 0xff0f | data >> 1 & 0x0050 | data << 1 & 0x00a0; break;
267
case 3:
268
newdata = data & 0xff0f | data >> 2 & 0x0030 | data << 1 & 0x0040 | data << 3 & 0x0080; break;
269
}
270
271
mSusie->SetButtonData(newdata);
272
}
273
274
SYNCFUNC(CSystem)
275
{
276
// mMemMap regenerates the mMemoryHandlers directly on load
277
278
TSS(mCart);
279
TSS(mRom);
280
TSS(mMemMap);
281
TSS(mRam);
282
TSS(mCpu);
283
TSS(mMikie);
284
TSS(mSusie);
285
286
NSS(gSuzieDoneTime);
287
NSS(gSystemCycleCount);
288
NSS(gNextTimerEvent);
289
NSS(gSystemIRQ);
290
NSS(gSystemNMI);
291
NSS(gSystemCPUSleep);
292
NSS(gSystemHalt);
293
NSS(frameoverflow);
294
}
295
296
297
/*
298
static MDFNSetting LynxSettings[] =
299
{
300
{ "lynx.rotateinput", MDFNSF_NOFLAGS, gettext_noop("Virtually rotate D-pad along with screen."), NULL, MDFNST_BOOL, "1" },
301
{ "lynx.lowpass", MDFNSF_CAT_SOUND, gettext_noop("Enable sound output lowpass filter."), NULL, MDFNST_BOOL, "1" },
302
{ NULL }
303
};
304
*/
305
306
/*
307
static const InputDeviceInputInfoStruct IDII[] =
308
{
309
{ "a", "A (outer)", 8, IDIT_BUTTON_CAN_RAPID, NULL },
310
{ "b", "B (inner)", 7, IDIT_BUTTON_CAN_RAPID, NULL },
311
{ "option_2", "Option 2 (lower)", 5, IDIT_BUTTON_CAN_RAPID, NULL },
312
{ "option_1", "Option 1 (upper)", 4, IDIT_BUTTON_CAN_RAPID, NULL },
313
314
{ "left", "LEFT ←", 2, IDIT_BUTTON, "right", { "up", "right", "down" } },
315
{ "right", "RIGHT →", 3, IDIT_BUTTON, "left", { "down", "left", "up" } },
316
{ "up", "UP ↑", 0, IDIT_BUTTON, "down", { "right", "down", "left" } },
317
{ "down", "DOWN ↓", 1, IDIT_BUTTON, "up", { "left", "up", "right" } },
318
{ "pause", "PAUSE", 6, IDIT_BUTTON, NULL },
319
};
320
*/
321
322
/*
323
static const FileExtensionSpecStruct KnownExtensions[] =
324
{
325
{ ".lnx", gettext_noop("Atari Lynx ROM Image") },
326
{ NULL, NULL }
327
};
328
*/
329
330
/*
331
MDFNGI EmulatedLynx =
332
{
333
"lynx",
334
"Atari Lynx",
335
KnownExtensions,
336
MODPRIO_INTERNAL_HIGH,
337
NULL,
338
&InputInfo,
339
Load,
340
TestMagic,
341
NULL,
342
NULL,
343
CloseGame,
344
SetLayerEnableMask,
345
NULL,
346
NULL,
347
NULL,
348
NULL,
349
NULL,
350
NULL,
351
NULL,
352
false,
353
StateAction,
354
Emulate,
355
SetInput,
356
DoSimpleCommand,
357
LynxSettings,
358
MDFN_MASTERCLOCK_FIXED(16000000),
359
0,
360
361
false, // Multires possible?
362
363
160, // lcm_width
364
102, // lcm_height
365
NULL, // Dummy
366
367
368
160, // Nominal width
369
102, // Nominal height
370
371
160, // Framebuffer width
372
102, // Framebuffer height
373
374
2, // Number of output sound channels
375
};
376
*/
377
378