Some coding style fixes
[jpcrr.git] / org / jpc / emulator / memory / LazyCodeBlockMemory.java
bloba5ae65441ac49e7527c6a361d768e76bacf3c580
1 /*
2 JPC-RR: A x86 PC Hardware Emulator
3 Release 1
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;
36 import java.io.*;
37 import org.jpc.emulator.memory.codeblock.*;
38 import org.jpc.emulator.processor.Processor;
40 /**
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
46 * @author Rhys Newman
47 * @author Ian Preston
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()
64 fpuHackFlag = true;
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))
84 return;
86 output.println("#" + output.objectNumber(this) + ": LazyCodeBlockMemory:");
87 dumpStatusPartial(output);
88 output.endObject();
91 public void dumpSRPartial(SRDumper output) throws IOException
93 super.dumpSRPartial(output);
94 output.dumpInt(size);
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
104 super(input);
105 size = input.loadInt();
106 buffer = input.loadArrayByte();
107 nullReadCount = input.loadInt();
108 codeBlockManager = (CodeBlockManager)input.loadObject();
109 fpuHackFlag = false;
110 if(input.objectEndsHere())
111 return;
112 fpuHackFlag = input.loadBoolean();
116 * Constructs an instance <code>size</code> bytes long.
117 * @param size
119 public LazyCodeBlockMemory(int size, CodeBlockManager manager) {
120 this.size = size;
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) {
146 int x86Count = 0;
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);
171 return x86Count;
174 public int executeReal(Processor cpu, int offset) {
175 int x86Count = 0;
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);
200 return x86Count;
203 public int executeVirtual8086(Processor cpu, int offset) {
204 int x86Count = 0;
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);
229 return x86Count;
232 private RealModeCodeBlock getRealModeCodeBlockAt(int offset) {
233 try {
234 return realCodeBuffer[offset];
235 } catch (NullPointerException e) {
236 constructRealCodeBlocksArray();
237 return realCodeBuffer[offset];
241 private ProtectedModeCodeBlock getProtectedModeCodeBlockAt(int offset) {
242 try {
243 return protectedCodeBuffer[offset];
244 } catch (NullPointerException e) {
245 constructProtectedCodeBlocksArray();
246 return protectedCodeBuffer[offset];
250 private Virtual8086ModeCodeBlock getVirtual8086ModeCodeBlockAt(int offset) {
251 try {
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))
263 return;
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) {
273 if(i < offset)
274 break;
275 else
276 continue;
278 if(virtual8086CodeBuffer[i] == PLACEHOLDER)
279 continue;
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))
294 return;
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) {
304 if(i < offset)
305 break;
306 else
307 continue;
309 if(protectedCodeBuffer[i] == PLACEHOLDER)
310 continue;
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))
325 return;
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) {
336 if(i < offset)
337 break;
338 else
339 continue;
341 if(realCodeBuffer[i] == PLACEHOLDER)
342 continue;
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);
356 if(block == null)
357 return;
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);
369 if(block == null)
370 return;
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);
382 if(block == null)
383 return;
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];
396 if(b == null) {
397 if(i < start)
398 break;
399 else
400 continue;
403 if(b == PLACEHOLDER)
404 continue;
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];
414 if(b == null) {
415 if(i < start)
416 break;
417 else
418 continue;
421 if(b == PLACEHOLDER)
422 continue;
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];
432 if(b == null) {
433 if(i < start)
434 break;
435 else
436 continue;
439 if(b == PLACEHOLDER)
440 continue;
442 if(!b.handleMemoryRegionChange(start, end))
443 removeVirtual8086CodeBlockAt(i);
448 public void clear()
450 realCodeBuffer = null;
451 protectedCodeBuffer = null;
452 virtual8086CodeBuffer = null;
453 buffer = 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()
468 return 0;
471 public int getX86Count()
473 return 0;
476 public int execute(Processor cpu)
478 throw executeException;
481 public boolean handleMemoryRegionChange(int startAddress, int endAddress)
483 return false;
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) {
500 allocateBuffer();
501 protectedCodeBuffer = new ProtectedModeCodeBlock[(int) getSize()];
503 ProtectedModeCodeBlock block = protectedCodeBuffer[offset];
504 if((block != null) && (block != PLACEHOLDER))
505 return block;
507 block = codeBlockManager.getProtectedModeCodeBlockAt(this, offset, size);
508 setProtectedCodeBlockAt(offset, block);
509 return block;
512 public Virtual8086ModeCodeBlock getVirtual8086Block(int offset)
514 if(virtual8086CodeBuffer == null) {
515 allocateBuffer();
516 virtual8086CodeBuffer = new Virtual8086ModeCodeBlock[(int) getSize()];
518 Virtual8086ModeCodeBlock block = virtual8086CodeBuffer[offset];
519 if((block != null) && (block != PLACEHOLDER))
520 return block;
522 block = codeBlockManager.getVirtual8086ModeCodeBlockAt(this, offset);
523 setVirtual8086CodeBlockAt(offset, block);
524 return block;
527 public RealModeCodeBlock getRealBlock(int offset)
529 if(realCodeBuffer == null) {
530 allocateBuffer();
531 realCodeBuffer = new RealModeCodeBlock[(int) getSize()];
533 RealModeCodeBlock block = realCodeBuffer[offset];
534 if((block != null) && (block != PLACEHOLDER))
535 return block;
537 block = codeBlockManager.getRealModeCodeBlockAt(this, offset);
538 setRealCodeBlockAt(offset, block);
539 return block;
542 //begin lazy memory methods
543 private final void allocateBuffer()
545 if(buffer == null)
546 buffer = new byte[size];
549 public void copyContentsIntoArray(int address, byte[] buf, int off, int len)
551 try {
552 System.arraycopy(buffer, address, buf, off, len);
553 } catch (NullPointerException e) {
554 if(++nullReadCount == ALLOCATION_THRESHOLD) {
555 allocateBuffer();
556 System.arraycopy(buffer, address, buf, off, len);
557 } else
558 Arrays.fill(buf, off, off + len, (byte) 0);
562 public void loadInitialContents(int address, byte[] buf, int off, int len)
564 try {
565 System.arraycopy(buf, off, buffer, address, len);
566 } catch (NullPointerException e) {
567 allocateBuffer();
568 System.arraycopy(buf, off, buffer, address, len);
572 public void copyArrayIntoContents(int address, byte[] buf, int off, int len)
574 try {
575 System.arraycopy(buf, off, buffer, address, len);
576 } catch (NullPointerException e) {
577 allocateBuffer();
578 System.arraycopy(buf, off, buffer, address, len);
580 regionAltered(address, address + len - 1);
583 public long getSize()
585 return size;
588 public boolean isAllocated()
590 return (buffer != null);
593 public byte getByte(int offset)
595 try {
596 if(fpuHackFlag && offset == 0x410) return (byte)(buffer[offset] & 0xFD);
598 return buffer[offset];
599 } catch (NullPointerException e) {
600 if(++nullReadCount == ALLOCATION_THRESHOLD) {
601 allocateBuffer();
602 return buffer[offset];
603 } else
604 return 0;
608 public void setByte(int offset, byte data) {
609 if(getByte(offset) == data)
610 return;
611 try {
612 buffer[offset] = data;
613 } catch (NullPointerException e) {
614 allocateBuffer();
615 buffer[offset] = data;
617 regionAltered(offset, offset);
620 public short getWord(int offset) {
621 try {
622 int result = 0xFF & buffer[offset];
623 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) {
632 allocateBuffer();
633 int result = 0xFF & buffer[offset];
634 offset++;
635 result |= buffer[offset] << 8;
636 return (short) result;
637 } else
638 return 0;
642 public int getDoubleWord(int offset) {
643 try {
644 int result = 0xFF & buffer[offset];
645 offset++;
646 result |= (0xFF & buffer[offset]) << 8;
647 offset++;
648 result |= (0xFF & buffer[offset]) << 16;
649 offset++;
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;
657 return result;
658 } catch (NullPointerException e) {
659 if(++nullReadCount == ALLOCATION_THRESHOLD) {
660 allocateBuffer();
661 int result = 0xFF & buffer[offset];
662 offset++;
663 result |= (0xFF & buffer[offset]) << 8;
664 offset++;
665 result |= (0xFF & buffer[offset]) << 16;
666 offset++;
667 result |= (buffer[offset]) << 24;
668 return result;
669 } else
670 return 0;
674 public void setWord(int offset, short data) {
675 if(getWord(offset) == data)
676 return;
677 try {
678 buffer[offset] = (byte) data;
679 offset++;
680 buffer[offset] = (byte) (data >> 8);
681 } catch (NullPointerException e) {
682 allocateBuffer();
683 buffer[offset] = (byte) data;
684 offset++;
685 buffer[offset] = (byte) (data >> 8);
687 regionAltered(offset, offset + 1);
690 public void setDoubleWord(int offset, int data) {
691 if(getDoubleWord(offset) == data)
692 return;
693 try {
694 buffer[offset] = (byte) data;
695 offset++;
696 data >>= 8;
697 buffer[offset] = (byte) (data);
698 offset++;
699 data >>= 8;
700 buffer[offset] = (byte) (data);
701 offset++;
702 data >>= 8;
703 buffer[offset] = (byte) (data);
704 } catch (NullPointerException e) {
705 allocateBuffer();
706 buffer[offset] = (byte) data;
707 offset++;
708 data >>= 8;
709 buffer[offset] = (byte) (data);
710 offset++;
711 data >>= 8;
712 buffer[offset] = (byte) (data);
713 offset++;
714 data >>= 8;
715 buffer[offset] = (byte) (data);
717 regionAltered(offset, offset + 3);