1 package com.tapina.robe.runtime;
2
3 import com.tapina.robe.module.RelocatableModuleArea;
4 import com.tapina.robe.module.Module;
5
6 import java.util.Iterator;
7 import java.util.Arrays;
8
9 /***
10 * This class encapsulates the logic for finding blocks of data in the memory map.
11 * It has been placed in a separate class as otherwise it makes a very long unwieldy method.
12 */
13 class BlockLocator {
14 final int address, length;
15 final boolean allowExtend;
16 final boolean allowCreate;
17 final Iterator iterator;
18
19 DataBlock blockBefore = null, blockAfter = null;
20 private MemoryMap memoryMap;
21
22 BlockLocator(MemoryMap memoryMap, int address, int length) {
23 this.memoryMap = memoryMap;
24 this.address = address;
25 this.length = length;
26 if (MemoryMap.isRomAddress(address)) {
27 iterator = Arrays.asList(MemoryMap.romModules).iterator();
28 allowExtend = allowCreate = false;
29 } else if (RelocatableModuleArea.isRmaAddress(address)) {
30 iterator = MemoryMap.rma.iterator();
31 allowExtend = allowCreate = false;
32 } else if (MemoryMap.isDynamicAreaAddress(address)) {
33 iterator = MemoryMap.dynamicAreas.iterator();
34 allowExtend = true;
35 allowCreate = false;
36 } else {
37 iterator = memoryMap.dataMap.values().iterator();
38 allowExtend = allowCreate = true;
39 }
40 }
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 DataBlock findDataBlock() {
56 findBeforeAndAfter();
57
58 if (blockBefore == null) {
59 MemoryMap.log.severe("findBlock() failing for address &" + Integer.toHexString(address));
60 }
61 return pickBlock();
62 }
63
64 private DataBlock pickBlock() {
65 final int blockBeforeStartAddress = blockBefore.getAddress();
66 final int blockBeforeEndAddress = blockBeforeStartAddress + blockBefore.getSize();
67 final int blockAfterStartAddress = blockAfter != null ? blockAfter.getAddress() : 0;
68 final int blockWantedEndAddress = address + length;
69 if (blockBeforeEndAddress >= blockWantedEndAddress) {
70
71 return blockBefore();
72 } else if (blockBeforeEndAddress > address) {
73
74 if (blockAfter != null && blockAfterStartAddress < blockWantedEndAddress) {
75 return joinBlocks(blockBeforeStartAddress, blockAfterStartAddress);
76 } else {
77
78 return extendBlockBefore(blockBeforeEndAddress);
79 }
80 } else if (blockAfter != null && blockAfterStartAddress < blockWantedEndAddress) {
81
82 return extendBlockAfter(blockAfterStartAddress);
83 } else {
84
85 return extendClosestOrCreate(blockBeforeEndAddress, blockAfterStartAddress);
86 }
87 }
88
89 private DataBlock extendClosestOrCreate(final int blockBeforeEndAddress, final int blockAfterAddress) {
90 int blockBeforeExtension = (address + length) - blockBeforeEndAddress;
91 int blockAfterExtension = blockAfterAddress - address;
92
93 if (blockBefore instanceof RawDataBlock && (blockAfter == null || blockBeforeExtension < blockAfterExtension)) {
94 return extendBlockBefore(blockBeforeEndAddress);
95 } else if (blockAfter instanceof RawDataBlock) {
96 return extendBlockAfter(blockAfterAddress);
97 } else if (allowCreate) {
98 return memoryMap.createDataBlock(address, length);
99 } else {
100 throw new AddressException(address);
101 }
102 }
103
104 private DataBlock extendBlockAfter(final int blockAfterAddress) {
105 if (allowExtend) {
106 ((RawDataBlock) blockAfter).extendBackwards(blockAfterAddress - address);
107 return blockAfter;
108 } else {
109 throw new AddressException(address);
110 }
111 }
112
113 private DataBlock extendBlockBefore(final int blockBeforeEndAddress) {
114 if (allowExtend) {
115 ((RawDataBlock) blockBefore).extendForwards((address + length) - blockBeforeEndAddress);
116 return blockBefore;
117 } else {
118 throw new AddressException(address);
119 }
120 }
121
122 private DataBlock joinBlocks(final int blockBeforeAddress, final int blockAfterStart) {
123 if (allowCreate) {
124
125 byte[] combinedData = new byte[blockAfterStart + blockAfter.getSize() - blockBeforeAddress];
126 System.arraycopy(blockBefore.getBytes(), 0, combinedData, 0, blockBefore.getSize());
127 System.arraycopy(blockAfter.getBytes(), 0, combinedData, blockAfterStart - blockBeforeAddress, blockAfter.getSize());
128 RawDataBlock dataBlock = new RawDataBlock(blockBeforeAddress, combinedData);
129 memoryMap.dataMap.put(new Integer(address), dataBlock);
130 memoryMap.dataMap.remove(new Integer(blockAfterStart));
131 return dataBlock;
132 } else {
133 throw new AddressException(address);
134 }
135 }
136
137 private DataBlock blockBefore() {
138 if (blockBefore instanceof Module) {
139 MemoryMap.log.fine("Reading data from inside module");
140 }
141 return blockBefore;
142 }
143
144 private void findBeforeAndAfter() {
145 while (iterator.hasNext()) {
146 final DataBlock block = (DataBlock) iterator.next();
147 if (block.getAddress() <= address) {
148 blockBefore = block;
149 } else {
150 blockAfter = block;
151 break;
152 }
153 }
154 }
155
156 }