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
))
328 realCodeBuffer
[offset
] = null;
329 int len
= b
.getX86Length();
330 for(int i
= offset
+ 1; (i
< offset
+ len
) && (i
< realCodeBuffer
.length
); i
++)
331 if(realCodeBuffer
[i
] == PLACEHOLDER
)
332 realCodeBuffer
[i
] = null;
334 for(int i
= Math
.min(offset
+ len
, realCodeBuffer
.length
) - 1; i
>= 0; i
--) {
335 if(realCodeBuffer
[i
] == null) {
341 if(realCodeBuffer
[i
] == PLACEHOLDER
)
344 RealModeCodeBlock bb
= realCodeBuffer
[i
];
345 len
= bb
.getX86Length();
347 for(int j
= i
+ 1; (j
< i
+ len
) && (j
< realCodeBuffer
.length
); j
++)
348 if(realCodeBuffer
[j
] == null)
349 realCodeBuffer
[j
] = PLACEHOLDER
;
353 private void setVirtual8086CodeBlockAt(int offset
, Virtual8086ModeCodeBlock block
)
355 removeVirtual8086CodeBlockAt(offset
);
359 virtual8086CodeBuffer
[offset
] = block
;
360 int len
= block
.getX86Length();
361 for(int i
= offset
+ 1; (i
< offset
+ len
) && (i
< virtual8086CodeBuffer
.length
); i
++)
362 if(virtual8086CodeBuffer
[i
] == null)
363 virtual8086CodeBuffer
[i
] = PLACEHOLDER
;
366 private void setProtectedCodeBlockAt(int offset
, ProtectedModeCodeBlock block
)
368 removeProtectedCodeBlockAt(offset
);
372 protectedCodeBuffer
[offset
] = block
;
373 int len
= block
.getX86Length();
374 for(int i
= offset
+ 1; (i
< offset
+ len
) && (i
< protectedCodeBuffer
.length
); i
++)
375 if(protectedCodeBuffer
[i
] == null)
376 protectedCodeBuffer
[i
] = PLACEHOLDER
;
379 private void setRealCodeBlockAt(int offset
, RealModeCodeBlock block
)
381 removeRealCodeBlockAt(offset
);
385 realCodeBuffer
[offset
] = block
;
386 int len
= block
.getX86Length();
387 for(int i
= offset
+ 1; (i
< offset
+ len
) && (i
< realCodeBuffer
.length
); i
++)
388 if(realCodeBuffer
[i
] == null)
389 realCodeBuffer
[i
] = PLACEHOLDER
;
392 private void regionAltered(int start
, int end
) {
393 if(realCodeBuffer
!= null) {
394 for(int i
= end
; i
>= 0; i
--) {
395 RealModeCodeBlock b
= realCodeBuffer
[i
];
406 if(!b
.handleMemoryRegionChange(start
, end
))
407 removeRealCodeBlockAt(i
);
411 if(protectedCodeBuffer
!= null) {
412 for(int i
= end
; i
>= 0; i
--) {
413 ProtectedModeCodeBlock b
= protectedCodeBuffer
[i
];
424 if(!b
.handleMemoryRegionChange(start
, end
))
425 removeProtectedCodeBlockAt(i
);
429 if(virtual8086CodeBuffer
!= null) {
430 for(int i
= end
; i
>= 0; i
--) {
431 Virtual8086ModeCodeBlock b
= virtual8086CodeBuffer
[i
];
442 if(!b
.handleMemoryRegionChange(start
, end
))
443 removeVirtual8086CodeBlockAt(i
);
450 realCodeBuffer
= null;
451 protectedCodeBuffer
= null;
452 virtual8086CodeBuffer
= null;
456 public String
toString()
458 return "LazyCodeBlockMemory[" + getSize() + "]";
461 //This class does not need to be dumpable because codeblocks can't be saved.
462 private static class BlankCodeBlock
implements RealModeCodeBlock
, ProtectedModeCodeBlock
, Virtual8086ModeCodeBlock
464 private static final RuntimeException executeException
= new NullPointerException();
466 public int getX86Length()
471 public int getX86Count()
476 public int execute(Processor cpu
)
478 throw executeException
;
481 public boolean handleMemoryRegionChange(int startAddress
, int endAddress
)
486 public String
getDisplayString()
488 return "\n\n<<Blank Block>>\n\n";
491 public String
toString()
493 return " -- Blank --\n";
497 public ProtectedModeCodeBlock
getProtectedBlock(int offset
, boolean size
)
499 if(protectedCodeBuffer
== null) {
501 protectedCodeBuffer
= new ProtectedModeCodeBlock
[(int) getSize()];
503 ProtectedModeCodeBlock block
= protectedCodeBuffer
[offset
];
504 if((block
!= null) && (block
!= PLACEHOLDER
))
507 block
= codeBlockManager
.getProtectedModeCodeBlockAt(this, offset
, size
);
508 setProtectedCodeBlockAt(offset
, block
);
512 public Virtual8086ModeCodeBlock
getVirtual8086Block(int offset
)
514 if(virtual8086CodeBuffer
== null) {
516 virtual8086CodeBuffer
= new Virtual8086ModeCodeBlock
[(int) getSize()];
518 Virtual8086ModeCodeBlock block
= virtual8086CodeBuffer
[offset
];
519 if((block
!= null) && (block
!= PLACEHOLDER
))
522 block
= codeBlockManager
.getVirtual8086ModeCodeBlockAt(this, offset
);
523 setVirtual8086CodeBlockAt(offset
, block
);
527 public RealModeCodeBlock
getRealBlock(int offset
)
529 if(realCodeBuffer
== null) {
531 realCodeBuffer
= new RealModeCodeBlock
[(int) getSize()];
533 RealModeCodeBlock block
= realCodeBuffer
[offset
];
534 if((block
!= null) && (block
!= PLACEHOLDER
))
537 block
= codeBlockManager
.getRealModeCodeBlockAt(this, offset
);
538 setRealCodeBlockAt(offset
, block
);
542 //begin lazy memory methods
543 private final void allocateBuffer()
546 buffer
= new byte[size
];
549 public void copyContentsIntoArray(int address
, byte[] buf
, int off
, int len
)
552 System
.arraycopy(buffer
, address
, buf
, off
, len
);
553 } catch (NullPointerException e
) {
554 if(++nullReadCount
== ALLOCATION_THRESHOLD
) {
556 System
.arraycopy(buffer
, address
, buf
, off
, len
);
558 Arrays
.fill(buf
, off
, off
+ len
, (byte) 0);
562 public void loadInitialContents(int address
, byte[] buf
, int off
, int len
)
565 System
.arraycopy(buf
, off
, buffer
, address
, len
);
566 } catch (NullPointerException e
) {
568 System
.arraycopy(buf
, off
, buffer
, address
, len
);
572 public void copyArrayIntoContents(int address
, byte[] buf
, int off
, int len
)
575 System
.arraycopy(buf
, off
, buffer
, address
, len
);
576 } catch (NullPointerException e
) {
578 System
.arraycopy(buf
, off
, buffer
, address
, len
);
580 regionAltered(address
, address
+ len
- 1);
583 public long getSize()
588 public boolean isAllocated()
590 return (buffer
!= null);
593 public byte getByte(int offset
)
596 if(fpuHackFlag
&& offset
== 0x410) return (byte)(buffer
[offset
] & 0xFD);
598 return buffer
[offset
];
599 } catch (NullPointerException e
) {
600 if(++nullReadCount
== ALLOCATION_THRESHOLD
) {
602 return buffer
[offset
];
608 public void setByte(int offset
, byte data
) {
609 if(getByte(offset
) == data
)
612 buffer
[offset
] = data
;
613 } catch (NullPointerException e
) {
615 buffer
[offset
] = data
;
617 regionAltered(offset
, offset
);
620 public short getWord(int offset
) {
622 int result
= 0xFF & buffer
[offset
];
624 result
|= buffer
[offset
] << 8;
626 if(fpuHackFlag
&& offset
== 0x411) result
&= 0xFFFD;
627 if(fpuHackFlag
&& offset
== 0x410) result
&= 0xFDFF;
629 return (short) result
;
630 } catch (NullPointerException e
) {
631 if(++nullReadCount
== ALLOCATION_THRESHOLD
) {
633 int result
= 0xFF & buffer
[offset
];
635 result
|= buffer
[offset
] << 8;
636 return (short) result
;
642 public int getDoubleWord(int offset
) {
644 int result
= 0xFF & buffer
[offset
];
646 result
|= (0xFF & buffer
[offset
]) << 8;
648 result
|= (0xFF & buffer
[offset
]) << 16;
650 result
|= (buffer
[offset
]) << 24;
652 if(fpuHackFlag
&& offset
== 0x413) result
&= 0xFFFFFFFD;
653 if(fpuHackFlag
&& offset
== 0x412) result
&= 0xFFFFFDFF;
654 if(fpuHackFlag
&& offset
== 0x411) result
&= 0xFFFDFFFF;
655 if(fpuHackFlag
&& offset
== 0x410) result
&= 0xFDFFFFFF;
658 } catch (NullPointerException e
) {
659 if(++nullReadCount
== ALLOCATION_THRESHOLD
) {
661 int result
= 0xFF & buffer
[offset
];
663 result
|= (0xFF & buffer
[offset
]) << 8;
665 result
|= (0xFF & buffer
[offset
]) << 16;
667 result
|= (buffer
[offset
]) << 24;
674 public void setWord(int offset
, short data
) {
675 if(getWord(offset
) == data
)
678 buffer
[offset
] = (byte) data
;
680 buffer
[offset
] = (byte) (data
>> 8);
681 } catch (NullPointerException e
) {
683 buffer
[offset
] = (byte) data
;
685 buffer
[offset
] = (byte) (data
>> 8);
687 regionAltered(offset
, offset
+ 1);
690 public void setDoubleWord(int offset
, int data
) {
691 if(getDoubleWord(offset
) == data
)
694 buffer
[offset
] = (byte) data
;
697 buffer
[offset
] = (byte) (data
);
700 buffer
[offset
] = (byte) (data
);
703 buffer
[offset
] = (byte) (data
);
704 } catch (NullPointerException e
) {
706 buffer
[offset
] = (byte) data
;
709 buffer
[offset
] = (byte) (data
);
712 buffer
[offset
] = (byte) (data
);
715 buffer
[offset
] = (byte) (data
);
717 regionAltered(offset
, offset
+ 3);