1/*****************************************************************************/
2/* */
3/* paravirt.c */
4/* */
5/* Paravirtualization for the sim65 6502 simulator */
6/* */
7/* */
8/* */
9/* (C) 2013-2013 Ullrich von Bassewitz */
10/* Römerstrasse 52 */
11/* D-70794 Filderstadt */
12/* EMail: uz@cc65.org */
13/* */
14/* */
15/* This software is provided 'as-is', without any expressed or implied */
16/* warranty. In no event will the authors be held liable for any damages */
17/* arising from the use of this software. */
18/* */
19/* Permission is granted to anyone to use this software for any purpose, */
20/* including commercial applications, and to alter it and redistribute it */
21/* freely, subject to the following restrictions: */
22/* */
23/* 1. The origin of this software must not be misrepresented; you must not */
24/* claim that you wrote the original software. If you use this software */
25/* in a product, an acknowledgment in the product documentation would be */
26/* appreciated but is not required. */
27/* 2. Altered source versions must be plainly marked as such, and must not */
28/* be misrepresented as being the original software. */
29/* 3. This notice may not be removed or altered from any source */
30/* distribution. */
31/* */
32/*****************************************************************************/
33
34
35
36#include <string.h>
37#include <stdlib.h>
38#include <fcntl.h>
39#include <sys/stat.h>
40#if defined(_WIN32)
41# define O_INITIAL O_BINARY
42#else
43# define O_INITIAL 0
44#endif
45#if defined(_MSC_VER)
46/* Microsoft compiler */
47# include <io.h>
48#else
49/* Anyone else */
50# include <unistd.h>
51#endif
52#ifndef S_IREAD
53# define S_IREAD S_IRUSR
54#endif
55#ifndef S_IWRITE
56# define S_IWRITE S_IWUSR
57#endif
58
59/* common */
60#include "cmdline.h"
61#include "print.h"
62#include "xmalloc.h"
63
64/* sim65 */
65#include "6502.h"
66#include "memory.h"
67#include "paravirt.h"
68
69
70
71/*****************************************************************************/
72/* Data */
73/*****************************************************************************/
74
75
76
77typedef void (*PVFunc) (CPURegs* Regs);
78
79static unsigned ArgStart;
80static unsigned char SPAddr;
81
82
83
84/*****************************************************************************/
85/* Code */
86/*****************************************************************************/
87
88
89
90static unsigned GetAX (CPURegs* Regs)
91{
92 return Regs->AC + (Regs->XR << 8);
93}
94
95
96
97static void SetAX (CPURegs* Regs, unsigned Val)
98{
99 Regs->AC = Val & 0xFF;
100 Val >>= 8;
101 Regs->XR = Val;
102}
103
104
105
106static unsigned char Pop (CPURegs* Regs)
107{
108 return MemReadByte (0x0100 + ++Regs->SP);
109}
110
111
112
113static unsigned PopParam (unsigned char Incr)
114{
115 unsigned SP = MemReadZPWord (SPAddr);
116 unsigned Val = MemReadWord (SP);
117 MemWriteWord (SPAddr, SP + Incr);
118 return Val;
119}
120
121
122
123static void PVExit (CPURegs* Regs)
124{
125 Print (stderr, 1, "PVExit ($%02X)\n", Regs->AC);
126 if (PrintCycles) {
127 Print (stdout, 0, "%lu cycles\n", GetCycles ());
128 }
129
130 exit (Regs->AC);
131}
132
133
134
135static void PVArgs (CPURegs* Regs)
136{
137 unsigned ArgC = ArgCount - ArgStart;
138 unsigned ArgV = GetAX (Regs);
139 unsigned SP = MemReadZPWord (SPAddr);
140 unsigned Args = SP - (ArgC + 1) * 2;
141
142 Print (stderr, 2, "PVArgs ($%04X)\n", ArgV);
143
144 MemWriteWord (ArgV, Args);
145
146 SP = Args;
147 while (ArgStart < ArgCount) {
148 unsigned I = 0;
149 const char* Arg = ArgVec[ArgStart++];
150 SP -= strlen (Arg) + 1;
151 do {
152 MemWriteByte (SP + I, Arg[I]);
153 }
154 while (Arg[I++]);
155
156 MemWriteWord (Args, SP);
157 Args += 2;
158 }
159 MemWriteWord (Args, SPAddr);
160
161 MemWriteWord (SPAddr, SP);
162 SetAX (Regs, ArgC);
163}
164
165
166
167static void PVOpen (CPURegs* Regs)
168{
169 char Path[1024];
170 int OFlag = O_INITIAL;
171 int OMode = 0;
172 unsigned RetVal, I = 0;
173
174 unsigned Mode = PopParam (Regs->YR - 4);
175 unsigned Flags = PopParam (2);
176 unsigned Name = PopParam (2);
177
178 if (Regs->YR - 4 < 2) {
179 /* If the caller didn't supply the mode
180 ** argument, use a reasonable default.
181 */
182 Mode = 0x01 | 0x02;
183 }
184
185 do {
186 Path[I] = MemReadByte (Name++);
187 }
188 while (Path[I++]);
189
190 Print (stderr, 2, "PVOpen (\"%s\", $%04X)\n", Path, Flags);
191
192 switch (Flags & 0x03) {
193 case 0x01:
194 OFlag |= O_RDONLY;
195 break;
196 case 0x02:
197 OFlag |= O_WRONLY;
198 break;
199 case 0x03:
200 OFlag |= O_RDWR;
201 break;
202 }
203 if (Flags & 0x10) {
204 OFlag |= O_CREAT;
205 }
206 if (Flags & 0x20) {
207 OFlag |= O_TRUNC;
208 }
209 if (Flags & 0x40) {
210 OFlag |= O_APPEND;
211 }
212 if (Flags & 0x80) {
213 OFlag |= O_EXCL;
214 }
215
216 if (Mode & 0x01) {
217 OMode |= S_IREAD;
218 }
219 if (Mode & 0x02) {
220 OMode |= S_IWRITE;
221 }
222
223 RetVal = open (Path, OFlag, OMode);
224
225 SetAX (Regs, RetVal);
226}
227
228
229
230static void PVClose (CPURegs* Regs)
231{
232 unsigned RetVal;
233
234 unsigned FD = GetAX (Regs);
235
236 Print (stderr, 2, "PVClose ($%04X)\n", FD);
237
238 RetVal = close (FD);
239
240 SetAX (Regs, RetVal);
241}
242
243
244
245static void PVRead (CPURegs* Regs)
246{
247 unsigned char* Data;
248 unsigned RetVal, I = 0;
249
250 unsigned Count = GetAX (Regs);
251 unsigned Buf = PopParam (2);
252 unsigned FD = PopParam (2);
253
254 Print (stderr, 2, "PVRead ($%04X, $%04X, $%04X)\n", FD, Buf, Count);
255
256 Data = xmalloc (Count);
257
258 RetVal = read (FD, Data, Count);
259
260 if (RetVal != (unsigned) -1) {
261 while (I < RetVal) {
262 MemWriteByte (Buf++, Data[I++]);
263 }
264 }
265 xfree (Data);
266
267 SetAX (Regs, RetVal);
268}
269
270
271
272static void PVWrite (CPURegs* Regs)
273{
274 unsigned char* Data;
275 unsigned RetVal, I = 0;
276
277 unsigned Count = GetAX (Regs);
278 unsigned Buf = PopParam (2);
279 unsigned FD = PopParam (2);
280
281 Print (stderr, 2, "PVWrite ($%04X, $%04X, $%04X)\n", FD, Buf, Count);
282
283 Data = xmalloc (Count);
284 while (I < Count) {
285 Data[I++] = MemReadByte (Buf++);
286 }
287
288 RetVal = write (FD, Data, Count);
289
290 xfree (Data);
291
292 SetAX (Regs, RetVal);
293}
294
295
296
297static const PVFunc Hooks[] = {
298 PVOpen,
299 PVClose,
300 PVRead,
301 PVWrite,
302 PVArgs,
303 PVExit,
304};
305
306
307
308void ParaVirtInit (unsigned aArgStart, unsigned char aSPAddr)
309/* Initialize the paravirtualization subsystem */
310{
311 ArgStart = aArgStart;
312 SPAddr = aSPAddr;
313};
314
315
316
317void ParaVirtHooks (CPURegs* Regs)
318/* Potentially execute paravirtualization hooks */
319{
320 /* Check for paravirtualization address range */
321 if (Regs->PC < PARAVIRT_BASE ||
322 Regs->PC >= PARAVIRT_BASE + sizeof (Hooks) / sizeof (Hooks[0])) {
323 return;
324 }
325
326 /* Call paravirtualization hook */
327 Hooks[Regs->PC - PARAVIRT_BASE] (Regs);
328
329 /* Simulate RTS */
330 Regs->PC = Pop(Regs) + (Pop(Regs) << 8) + 1;
331}
332