2 JPC-RR: A x86 PC Hardware Emulator
5 Copyright (C) 2007-2009 Isis Innovation Limited
6 Copyright (C) 2009-2010 H. Ilari Liusvaara
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License version 2 as published by
10 the Free Software Foundation.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 Based on JPC x86 PC Hardware emulator,
22 A project from the Physics Dept, The University of Oxford
24 Details about original JPC can be found at:
26 www-jpc.physics.ox.ac.uk
30 package org
.jpc
.emulator
.memory
;
32 import org
.jpc
.emulator
.StatusDumper
;
33 import org
.jpc
.emulator
.SRLoader
;
34 import org
.jpc
.emulator
.SRDumper
;
35 import java
.util
.Arrays
;
37 import org
.jpc
.emulator
.memory
.codeblock
.*;
38 import org
.jpc
.emulator
.processor
.Processor
;
41 * <code>Memory</code> object with simple execute capabilities. Uses a
42 * {@link org.jpc.emulator.memory.codeblock.CodeBlockManager} instance to generate
43 * {@link org.jpc.emulator.memory.codeblock.CodeBlock} objects which are then
44 * stored in mirror arrays of the memory structure.
45 * @author Chris Dennis
49 public class LazyCodeBlockMemory
extends AbstractMemory
{
51 private CodeBlockManager codeBlockManager
;
52 private static final BlankCodeBlock PLACEHOLDER
= new BlankCodeBlock();
53 private RealModeCodeBlock
[] realCodeBuffer
;
54 private ProtectedModeCodeBlock
[] protectedCodeBuffer
;
55 private Virtual8086ModeCodeBlock
[] virtual8086CodeBuffer
;
56 private static final int ALLOCATION_THRESHOLD
= 10;
57 private final int size
;
58 private byte[] buffer
= null;
59 private int nullReadCount
= 0;
60 private boolean fpuHackFlag
;
62 public void setFPUHack()
67 public boolean isDirty()
69 return (buffer
!= null);
72 public void dumpStatusPartial(StatusDumper output
)
74 super.dumpStatusPartial(output
);
75 output
.println("\tsize " + size
+ " nullReadCount " + nullReadCount
);
76 output
.println("\tbuffer:");
77 output
.printArray(buffer
, "buffer");
78 //Skip the codeblocks. They are cache.
81 public void dumpStatus(StatusDumper output
)
83 if(output
.dumped(this))
86 output
.println("#" + output
.objectNumber(this) + ": LazyCodeBlockMemory:");
87 dumpStatusPartial(output
);
91 public void dumpSRPartial(SRDumper output
) throws IOException
93 super.dumpSRPartial(output
);
95 output
.dumpArray(buffer
);
96 output
.dumpInt(nullReadCount
);
97 output
.dumpObject(codeBlockManager
);
98 output
.dumpBoolean(fpuHackFlag
);
99 //Skip the codeblocks. They are cache.
102 public LazyCodeBlockMemory(SRLoader input
) throws IOException
105 size
= input
.loadInt();
106 buffer
= input
.loadArrayByte();
107 nullReadCount
= input
.loadInt();
108 codeBlockManager
= (CodeBlockManager
)input
.loadObject();
110 if(input
.objectEndsHere())
112 fpuHackFlag
= input
.loadBoolean();
116 * Constructs an instance <code>size</code> bytes long.
119 public LazyCodeBlockMemory(int size
, CodeBlockManager manager
) {
121 this.codeBlockManager
= manager
;
125 * Should probably be made private.
127 protected void constructCodeBlocksArray() {
128 realCodeBuffer
= new RealModeCodeBlock
[(int) getSize()];
129 protectedCodeBuffer
= new ProtectedModeCodeBlock
[(int) getSize()];
130 virtual8086CodeBuffer
= new Virtual8086ModeCodeBlock
[(int) getSize()];
133 private void constructRealCodeBlocksArray() {
134 realCodeBuffer
= new RealModeCodeBlock
[(int) getSize()];
137 private void constructVirtual8086CodeBlocksArray() {
138 virtual8086CodeBuffer
= new Virtual8086ModeCodeBlock
[(int) getSize()];
141 private void constructProtectedCodeBlocksArray() {
142 protectedCodeBuffer
= new ProtectedModeCodeBlock
[(int) getSize()];
145 public int executeProtected(Processor cpu
, int offset
) {
147 int ip
= cpu
.getInstructionPointer();
149 offset
= ip
& AddressSpace
.BLOCK_MASK
;
150 ProtectedModeCodeBlock block
= getProtectedModeCodeBlockAt(offset
);
155 x86Count
+= block
.execute(cpu
);
157 catch (NullPointerException e
)
159 block
= codeBlockManager
.getProtectedModeCodeBlockAt(this, offset
, cpu
.cs
.getDefaultSizeFlag());
160 setProtectedCodeBlockAt(offset
, block
);
161 x86Count
+= block
.execute(cpu
);
164 catch (CodeBlockReplacementException e
)
166 block
= (ProtectedModeCodeBlock
) e
.getReplacement();
167 protectedCodeBuffer
[offset
] = block
;
168 x86Count
+= block
.execute(cpu
);
174 public int executeReal(Processor cpu
, int offset
) {
176 int ip
= cpu
.getInstructionPointer();
178 offset
= ip
& AddressSpace
.BLOCK_MASK
;
179 RealModeCodeBlock block
= getRealModeCodeBlockAt(offset
);
184 x86Count
+= block
.execute(cpu
);
186 catch (NullPointerException e
)
188 block
= codeBlockManager
.getRealModeCodeBlockAt(this, offset
);
189 setRealCodeBlockAt(offset
, block
);
190 x86Count
+= block
.execute(cpu
);
193 catch (CodeBlockReplacementException e
)
195 block
= (RealModeCodeBlock
) e
.getReplacement();
196 realCodeBuffer
[offset
] = block
;
197 x86Count
+= block
.execute(cpu
);
203 public int executeVirtual8086(Processor cpu
, int offset
) {
205 int ip
= cpu
.getInstructionPointer();
207 offset
= ip
& AddressSpace
.BLOCK_MASK
;
208 Virtual8086ModeCodeBlock block
= getVirtual8086ModeCodeBlockAt(offset
);
213 x86Count
+= block
.execute(cpu
);
215 catch (NullPointerException e
)
217 block
= codeBlockManager
.getVirtual8086ModeCodeBlockAt(this, offset
);
218 setVirtual8086CodeBlockAt(offset
, block
);
219 x86Count
+= block
.execute(cpu
);
222 catch (CodeBlockReplacementException e
)
224 block
= (Virtual8086ModeCodeBlock
) e
.getReplacement();
225 virtual8086CodeBuffer
[offset
] = block
;
226 x86Count
+= block
.execute(cpu
);
232 private RealModeCodeBlock
getRealModeCodeBlockAt(int offset
) {
234 return realCodeBuffer
[offset
];
235 } catch (NullPointerException e
) {
236 constructRealCodeBlocksArray();
237 return realCodeBuffer
[offset
];
241 private ProtectedModeCodeBlock
getProtectedModeCodeBlockAt(int offset
) {
243 return protectedCodeBuffer
[offset
];
244 } catch (NullPointerException e
) {
245 constructProtectedCodeBlocksArray();
246 return protectedCodeBuffer
[offset
];
250 private Virtual8086ModeCodeBlock
getVirtual8086ModeCodeBlockAt(int offset
) {
252 return virtual8086CodeBuffer
[offset
];
253 } catch (NullPointerException e
) {
254 constructVirtual8086CodeBlocksArray();
255 return virtual8086CodeBuffer
[offset
];
259 private void removeVirtual8086CodeBlockAt(int offset
)
261 Virtual8086ModeCodeBlock b
= virtual8086CodeBuffer
[offset
];
262 if((b
== null) || (b
== PLACEHOLDER
))
265 virtual8086CodeBuffer
[offset
] = null;
266 int len
= b
.getX86Length();
267 for(int i
= offset
+ 1; (i
< offset
+ len
) && (i
< virtual8086CodeBuffer
.length
); i
++)
268 if(virtual8086CodeBuffer
[i
] == PLACEHOLDER
)
269 virtual8086CodeBuffer
[i
] = null;
271 for(int i
= Math
.min(offset
+ len
, virtual8086CodeBuffer
.length
) - 1; i
>= 0; i
--) {
272 if(virtual8086CodeBuffer
[i
] == null) {
278 if(virtual8086CodeBuffer
[i
] == PLACEHOLDER
)
281 Virtual8086ModeCodeBlock bb
= virtual8086CodeBuffer
[i
];
282 len
= bb
.getX86Length();
284 for(int j
= i
+ 1; (j
< i
+ len
) && (j
< virtual8086CodeBuffer
.length
); j
++)
285 if(virtual8086CodeBuffer
[j
] == null)
286 virtual8086CodeBuffer
[j
] = PLACEHOLDER
;
290 private void removeProtectedCodeBlockAt(int offset
)
292 ProtectedModeCodeBlock b
= protectedCodeBuffer
[offset
];
293 if((b
== null) || (b
== PLACEHOLDER
))
296 protectedCodeBuffer
[offset
] = null;
297 int len
= b
.getX86Length();
298 for(int i
= offset
+ 1; (i
< offset
+ len
) && (i
< protectedCodeBuffer
.length
); i
++)
299 if(protectedCodeBuffer
[i
] == PLACEHOLDER
)
300 protectedCodeBuffer
[i
] = null;
302 for(int i
= Math
.min(offset
+ len
, protectedCodeBuffer
.length
) - 1; i
>= 0; i
--) {
303 if(protectedCodeBuffer
[i
] == null) {
309 if(protectedCodeBuffer
[i
] == PLACEHOLDER
)
312 ProtectedModeCodeBlock bb
= protectedCodeBuffer
[i
];
313 len
= bb
.getX86Length();
315 for(int j
= i
+ 1; (j
< i
+ len
) && (j
< protectedCodeBuffer
.length
); j
++)
316 if(protectedCodeBuffer
[j
] == null)
317 protectedCodeBuffer
[j
] = PLACEHOLDER
;
321 private void removeRealCodeBlockAt(int offset
)
323 RealModeCodeBlock b
= realCodeBuffer
[offset
];
324 if((b
== null) || (b
== PLACEHOLDER
))
327 realCodeBuffer
[offset
] = null;
328 int len
= b
.getX86Length();
329 for(int i
= offset
+ 1; (i
< offset
+ len
) && (i
< realCodeBuffer
.length
); i
++)
330 if(realCodeBuffer
[i
] == PLACEHOLDER
)
331 realCodeBuffer
[i
] = null;
333 for(int i
= Math
.min(offset
+ len
, realCodeBuffer
.length
) - 1; i
>= 0; i
--) {
334 if(realCodeBuffer
[i
] == null) {
340 if(realCodeBuffer
[i
] == PLACEHOLDER
)
343 RealModeCodeBlock bb
= realCodeBuffer
[i
];
344 len
= bb
.getX86Length();
346 for(int j
= i
+ 1; (j
< i
+ len
) && (j
< realCodeBuffer
.length
); j
++)
347 if(realCodeBuffer
[j
] == null)
348 realCodeBuffer
[j
] = PLACEHOLDER
;
352 private void setVirtual8086CodeBlockAt(int offset
, Virtual8086ModeCodeBlock block
)
354 removeVirtual8086CodeBlockAt(offset
);
358 virtual8086CodeBuffer
[offset
] = block
;
359 int len
= block
.getX86Length();
360 for(int i
= offset
+ 1; (i
< offset
+ len
) && (i
< virtual8086CodeBuffer
.length
); i
++)
361 if(virtual8086CodeBuffer
[i
] == null)
362 virtual8086CodeBuffer
[i
] = PLACEHOLDER
;
365 private void setProtectedCodeBlockAt(int offset
, ProtectedModeCodeBlock block
)
367 removeProtectedCodeBlockAt(offset
);
371 protectedCodeBuffer
[offset
] = block
;
372 int len
= block
.getX86Length();
373 for(int i
= offset
+ 1; (i
< offset
+ len
) && (i
< protectedCodeBuffer
.length
); i
++)
374 if(protectedCodeBuffer
[i
] == null)
375 protectedCodeBuffer
[i
] = PLACEHOLDER
;
378 private void setRealCodeBlockAt(int offset
, RealModeCodeBlock block
)
380 removeRealCodeBlockAt(offset
);
384 realCodeBuffer
[offset
] = block
;
385 int len
= block
.getX86Length();
386 for(int i
= offset
+ 1; (i
< offset
+ len
) && (i
< realCodeBuffer
.length
); i
++)
387 if(realCodeBuffer
[i
] == null)
388 realCodeBuffer
[i
] = PLACEHOLDER
;
391 private void regionAltered(int start
, int end
) {
392 if(realCodeBuffer
!= null) {
393 for(int i
= end
; i
>= 0; i
--) {
394 RealModeCodeBlock b
= realCodeBuffer
[i
];
405 if(!b
.handleMemoryRegionChange(start
, end
)) {
406 removeRealCodeBlockAt(i
);
412 if(protectedCodeBuffer
!= null) {
413 for(int i
= end
; i
>= 0; i
--) {
414 ProtectedModeCodeBlock b
= protectedCodeBuffer
[i
];
425 if(!b
.handleMemoryRegionChange(start
, end
)) {
426 removeProtectedCodeBlockAt(i
);
432 if(virtual8086CodeBuffer
!= null) {
433 for(int i
= end
; i
>= 0; i
--) {
434 Virtual8086ModeCodeBlock b
= virtual8086CodeBuffer
[i
];
445 if(!b
.handleMemoryRegionChange(start
, end
)) {
446 removeVirtual8086CodeBlockAt(i
);
455 realCodeBuffer
= null;
456 protectedCodeBuffer
= null;
457 virtual8086CodeBuffer
= null;
461 public String
toString()
463 return "LazyCodeBlockMemory[" + getSize() + "]";
466 //This class does not need to be dumpable because codeblocks can't be saved.
467 private static class BlankCodeBlock
implements RealModeCodeBlock
, ProtectedModeCodeBlock
, Virtual8086ModeCodeBlock
469 private static final RuntimeException executeException
= new NullPointerException();
471 public int getX86Length()
476 public int getX86Count()
481 public int execute(Processor cpu
)
483 throw executeException
;
486 public void invalidate()
490 public boolean handleMemoryRegionChange(int startAddress
, int endAddress
)
495 public String
getDisplayString()
497 return "\n\n<<Blank Block>>\n\n";
500 public String
toString()
502 return " -- Blank --\n";
506 public ProtectedModeCodeBlock
getProtectedBlock(int offset
, boolean size
)
508 if(protectedCodeBuffer
== null) {
510 protectedCodeBuffer
= new ProtectedModeCodeBlock
[(int) getSize()];
512 ProtectedModeCodeBlock block
= protectedCodeBuffer
[offset
];
513 if((block
!= null) && (block
!= PLACEHOLDER
))
516 block
= codeBlockManager
.getProtectedModeCodeBlockAt(this, offset
, size
);
517 setProtectedCodeBlockAt(offset
, block
);
521 public Virtual8086ModeCodeBlock
getVirtual8086Block(int offset
)
523 if(virtual8086CodeBuffer
== null) {
525 virtual8086CodeBuffer
= new Virtual8086ModeCodeBlock
[(int) getSize()];
527 Virtual8086ModeCodeBlock block
= virtual8086CodeBuffer
[offset
];
528 if((block
!= null) && (block
!= PLACEHOLDER
))
531 block
= codeBlockManager
.getVirtual8086ModeCodeBlockAt(this, offset
);
532 setVirtual8086CodeBlockAt(offset
, block
);
536 public RealModeCodeBlock
getRealBlock(int offset
)
538 if(realCodeBuffer
== null) {
540 realCodeBuffer
= new RealModeCodeBlock
[(int) getSize()];
542 RealModeCodeBlock block
= realCodeBuffer
[offset
];
543 if((block
!= null) && (block
!= PLACEHOLDER
))
546 block
= codeBlockManager
.getRealModeCodeBlockAt(this, offset
);
547 setRealCodeBlockAt(offset
, block
);
551 //begin lazy memory methods
552 private final void allocateBuffer()
555 buffer
= new byte[size
];
558 public void copyContentsIntoArray(int address
, byte[] buf
, int off
, int len
)
561 System
.arraycopy(buffer
, address
, buf
, off
, len
);
562 } catch (NullPointerException e
) {
563 if(++nullReadCount
== ALLOCATION_THRESHOLD
) {
565 System
.arraycopy(buffer
, address
, buf
, off
, len
);
567 Arrays
.fill(buf
, off
, off
+ len
, (byte) 0);
571 public void loadInitialContents(int address
, byte[] buf
, int off
, int len
)
574 System
.arraycopy(buf
, off
, buffer
, address
, len
);
575 } catch (NullPointerException e
) {
577 System
.arraycopy(buf
, off
, buffer
, address
, len
);
581 public void copyArrayIntoContents(int address
, byte[] buf
, int off
, int len
)
584 System
.arraycopy(buf
, off
, buffer
, address
, len
);
585 } catch (NullPointerException e
) {
587 System
.arraycopy(buf
, off
, buffer
, address
, len
);
589 regionAltered(address
, address
+ len
- 1);
592 public long getSize()
597 public boolean isAllocated()
599 return (buffer
!= null);
602 public byte getByte(int offset
)
605 if(fpuHackFlag
&& offset
== 0x410) return (byte)(buffer
[offset
] & 0xFD);
607 return buffer
[offset
];
608 } catch (NullPointerException e
) {
609 if(++nullReadCount
== ALLOCATION_THRESHOLD
) {
611 return buffer
[offset
];
617 public void setByte(int offset
, byte data
) {
618 if(getByte(offset
) == data
)
621 buffer
[offset
] = data
;
622 } catch (NullPointerException e
) {
624 buffer
[offset
] = data
;
626 regionAltered(offset
, offset
);
629 public short getWord(int offset
) {
631 int result
= 0xFF & buffer
[offset
];
633 result
|= buffer
[offset
] << 8;
635 if(fpuHackFlag
&& offset
== 0x411) result
&= 0xFFFD;
636 if(fpuHackFlag
&& offset
== 0x410) result
&= 0xFDFF;
638 return (short) result
;
639 } catch (NullPointerException e
) {
640 if(++nullReadCount
== ALLOCATION_THRESHOLD
) {
642 int result
= 0xFF & buffer
[offset
];
644 result
|= buffer
[offset
] << 8;
645 return (short) result
;
651 public int getDoubleWord(int offset
) {
653 int result
= 0xFF & buffer
[offset
];
655 result
|= (0xFF & buffer
[offset
]) << 8;
657 result
|= (0xFF & buffer
[offset
]) << 16;
659 result
|= (buffer
[offset
]) << 24;
661 if(fpuHackFlag
&& offset
== 0x413) result
&= 0xFFFFFFFD;
662 if(fpuHackFlag
&& offset
== 0x412) result
&= 0xFFFFFDFF;
663 if(fpuHackFlag
&& offset
== 0x411) result
&= 0xFFFDFFFF;
664 if(fpuHackFlag
&& offset
== 0x410) result
&= 0xFDFFFFFF;
667 } catch (NullPointerException e
) {
668 if(++nullReadCount
== ALLOCATION_THRESHOLD
) {
670 int result
= 0xFF & buffer
[offset
];
672 result
|= (0xFF & buffer
[offset
]) << 8;
674 result
|= (0xFF & buffer
[offset
]) << 16;
676 result
|= (buffer
[offset
]) << 24;
683 public void setWord(int offset
, short data
) {
684 if(getWord(offset
) == data
)
687 buffer
[offset
] = (byte) data
;
689 buffer
[offset
] = (byte) (data
>> 8);
690 } catch (NullPointerException e
) {
692 buffer
[offset
] = (byte) data
;
694 buffer
[offset
] = (byte) (data
>> 8);
696 regionAltered(offset
, offset
+ 1);
699 public void setDoubleWord(int offset
, int data
) {
700 if(getDoubleWord(offset
) == data
)
703 buffer
[offset
] = (byte) data
;
706 buffer
[offset
] = (byte) (data
);
709 buffer
[offset
] = (byte) (data
);
712 buffer
[offset
] = (byte) (data
);
713 } catch (NullPointerException e
) {
715 buffer
[offset
] = (byte) data
;
718 buffer
[offset
] = (byte) (data
);
721 buffer
[offset
] = (byte) (data
);
724 buffer
[offset
] = (byte) (data
);
726 regionAltered(offset
, offset
+ 3);