diff --git a/src/rars/Globals.java b/src/rars/Globals.java index 759ad171..45098a92 100644 --- a/src/rars/Globals.java +++ b/src/rars/Globals.java @@ -4,9 +4,12 @@ import rars.riscv.hardware.Memory; import rars.riscv.InstructionSet; import rars.riscv.SyscallNumberOverride; +import rars.riscv.hardware.MemoryConfiguration; +import rars.riscv.hardware.MemoryConfigurations; import rars.util.PropertiesFile; import rars.venus.VenusUI; +import java.io.ByteArrayInputStream; import java.util.ArrayList; import java.util.Enumeration; import java.util.Properties; @@ -173,6 +176,12 @@ public static void initialize(boolean gui) { settings = new Settings(gui); initialized = true; debug = false; + String tmp = settings.getMemoryCustomConfiguration(); + if(!tmp.equals("")){ + MemoryConfiguration mc = MemoryConfigurations.loadNewConfig(new ByteArrayInputStream(tmp.getBytes())); + if (mc != null) MemoryConfigurations.addNewConfig(mc); + } + MemoryConfigurations.setCurrentConfiguration(MemoryConfigurations.getConfigurationByName(settings.getMemoryConfiguration())); memory.clear(); // will establish memory configuration from setting } } diff --git a/src/rars/Launch.java b/src/rars/Launch.java index 08174554..9fd424b4 100644 --- a/src/rars/Launch.java +++ b/src/rars/Launch.java @@ -4,23 +4,16 @@ import rars.riscv.dump.DumpFormat; import rars.riscv.dump.DumpFormatLoader; import rars.riscv.hardware.*; -import rars.simulator.ProgramArgumentList; import rars.simulator.Simulator; import rars.util.Binary; import rars.util.FilenameFinder; -import rars.util.MemoryDump; import rars.venus.VenusUI; import rars.api.Options; import javax.swing.*; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.PrintStream; +import java.io.*; import java.util.ArrayList; import java.util.Iterator; -import java.util.Observable; -import java.util.Observer; /* Copyright (c) 2003-2012, Pete Sanderson and Kenneth Vollmar @@ -175,14 +168,12 @@ private void dumpSegments(Program program) { for (String[] triple : dumpTriples) { File file = new File(triple[2]); - Integer[] segInfo = MemoryDump.getSegmentBounds(triple[0]); + Range segInfo = Memory.configuration.sections.get(triple[0]); // If not segment name, see if it is address range instead. DPS 14-July-2008 if (segInfo == null) { try { String[] memoryRange = checkMemoryAddressRange(triple[0]); - segInfo = new Integer[2]; - segInfo[0] = Binary.stringToInt(memoryRange[0]); // low end of range - segInfo[1] = Binary.stringToInt(memoryRange[1]); // high end of range + segInfo = new Range(Binary.stringToInt(memoryRange[0]),Binary.stringToInt(memoryRange[1])); } catch (NumberFormatException nfe) { segInfo = null; } catch (NullPointerException npe) { @@ -199,12 +190,12 @@ private void dumpSegments(Program program) { continue; } try { - int highAddress = program.getMemory().getAddressOfFirstNull(segInfo[0], segInfo[1]) - Memory.WORD_LENGTH_BYTES; - if (highAddress < segInfo[0]) { + int highAddress = program.getMemory().getAddressOfFirstNull(segInfo.low, segInfo.high) - Memory.WORD_LENGTH_BYTES; + if (highAddress < segInfo.low) { out.println("This segment has not been written to, there is nothing to dump."); continue; } - format.dumpMemoryRange(file, segInfo[0], highAddress, program.getMemory()); + format.dumpMemoryRange(file, segInfo.low, highAddress, program.getMemory()); } catch (FileNotFoundException e) { out.println("Error while attempting to save dump, file " + file + " was not found!"); } catch (AddressErrorException e) { @@ -297,8 +288,17 @@ private boolean parseCommandArgs(String[] args) { String configName = args[++i]; MemoryConfiguration config = MemoryConfigurations.getConfigurationByName(configName); if (config == null) { - out.println("Invalid memory configuration: " + configName); - argsOK = false; + String error = ""; + try { + config = MemoryConfigurations.loadNewConfig(new FileInputStream(new File(configName))); + if (config == null) error = " does not define a well specified config"; + }catch(FileNotFoundException fe) { + error = " is not the name of a known config or a valid file path"; + } + if(config == null) { + out.println("Invalid memory configuration: " + configName + error) ; + argsOK = false; + } } else { MemoryConfigurations.setCurrentConfiguration(config); } @@ -672,7 +672,7 @@ private void displayCopyright(String[] args, String noCopyrightSwitch) { // Display command line help text private void displayHelp() { - String[] segmentNames = MemoryDump.getSegmentNames(); + String[] segmentNames = new String[]{".text",".data"}; String segments = ""; for (int i = 0; i < segmentNames.length; i++) { segments += segmentNames[i]; @@ -708,8 +708,9 @@ private void displayHelp() { out.println(" mc -- set memory configuration. Argument is"); out.println(" case-sensitive and possible values are: Default for the default"); out.println(" 32-bit address space, CompactDataAtZero for a 32KB memory with"); - out.println(" data segment at address 0, or CompactTextAtZero for a 32KB"); - out.println(" memory with text segment at address 0."); + out.println(" data segment at address 0, CompactTextAtZero for a 32KB"); + out.println(" memory with text segment at address 0, the name of a custom"); + out.println(" configuration, or a path to a config file."); out.println(" me -- display RARS messages to standard err instead of standard out. "); out.println(" Can separate messages from program output using redirection"); out.println(" nc -- do not display copyright notice (for cleaner redirected/piped output)."); diff --git a/src/rars/Settings.java b/src/rars/Settings.java index de31460a..af15c386 100644 --- a/src/rars/Settings.java +++ b/src/rars/Settings.java @@ -1,5 +1,7 @@ package rars; +import rars.riscv.hardware.MemoryConfiguration; +import rars.riscv.hardware.MemoryConfigurations; import rars.util.Binary; import rars.util.EditorFont; import rars.venus.editors.jeditsyntax.SyntaxStyle; @@ -199,8 +201,14 @@ String getName() { * Number of letters to be matched by editor's instruction guide before popup generated (if popup enabled) */ public static final int EDITOR_POPUP_PREFIX_LENGTH = 6; + + /** + * String representing a custom memory config property file + */ + public static final int CUSTOM_MEMORY_CONFIG = 7; + // Match the above by position. - private static final String[] stringSettingsKeys = {"ExceptionHandler", "TextColumnOrder", "LabelSortState", "MemoryConfiguration", "CaretBlinkRate", "EditorTabSize", "EditorPopupPrefixLength"}; + private static final String[] stringSettingsKeys = {"ExceptionHandler", "TextColumnOrder", "LabelSortState", "MemoryConfiguration", "CaretBlinkRate", "EditorTabSize", "EditorPopupPrefixLength", "CustomMemoryConfig"}; /** * Last resort default values for String settings; @@ -208,7 +216,7 @@ String getName() { * If you wish to change, do so before instantiating the Settings object. * Must match key by list position. */ - private static String[] defaultStringSettingsValues = {"", "0 1 2 3 4", "0", "", "500", "8", "2"}; + private static String[] defaultStringSettingsValues = {"", "0 1 2 3 4", "0", "", "500", "8", "2",""}; // FONT SETTINGS. Each array position has associated name. @@ -551,6 +559,16 @@ public String getMemoryConfiguration() { return stringSettingsValues[MEMORY_CONFIGURATION]; } + /** + * Returns a properties file contents representing a custom memory configuration + * + * @return a memory configuration, empty if none. + */ + public String getMemoryCustomConfiguration() { + return stringSettingsValues[CUSTOM_MEMORY_CONFIG]; + } + + /** * Current editor font. Retained for compatibility but replaced * by: getFontByPosition(Settings.EDITOR_FONT) @@ -773,6 +791,10 @@ public void setExceptionHandler(String newFilename) { public void setMemoryConfiguration(String config) { setStringSetting(MEMORY_CONFIGURATION, config); + MemoryConfiguration tmp = MemoryConfigurations.getConfigurationByName(config); + if (tmp != null && !tmp.builtin) { + setStringSetting(CUSTOM_MEMORY_CONFIG, tmp.toPropertiesString()); + } } /** diff --git a/src/rars/assembler/Assembler.java b/src/rars/assembler/Assembler.java index fa88542b..4e0fe596 100644 --- a/src/rars/assembler/Assembler.java +++ b/src/rars/assembler/Assembler.java @@ -65,7 +65,20 @@ public class Assembler { private AddressSpace dataAddress; private DataSegmentForwardReferences currentFileDataSegmentForwardReferences, accumulatedDataSegmentForwardReferences; - + private ArrayList datalist; + class DataStruct { + int address, data, size; + ErrorMessage iffails; + DataStruct(int address, int data, int size, ErrorMessage iffails){ + this.address = address; + this.data = data; + this.size = size; + this.iffails = iffails; + } + } + private void setData(int address, int data, int size, ErrorMessage iffails){ + datalist.add(new DataStruct(address,data,size,iffails)); + } /** * Get list of assembler errors and warnings * @@ -99,14 +112,15 @@ public ArrayList assemble(ArrayList tokenizedPro if (tokenizedProgramFiles == null || tokenizedProgramFiles.size() == 0) return null; - textAddress = new AddressSpace(Memory.textBaseAddress); - dataAddress = new AddressSpace(Memory.dataBaseAddress); - externAddress = Memory.externBaseAddress; + textAddress = new AddressSpace(Memory.configuration.getTextBaseAddress()); + dataAddress = new AddressSpace(Memory.configuration.getDataBaseAddress()); + externAddress = Memory.configuration.getExternBaseAddress(); currentFileDataSegmentForwardReferences = new DataSegmentForwardReferences(); accumulatedDataSegmentForwardReferences = new DataSegmentForwardReferences(); Globals.symbolTable.clear(); Globals.memory.clear(); ArrayList machineList = new ArrayList<>(); + datalist = new ArrayList<>(); this.errors = new ErrorList(); if (Globals.debug) System.out.println("Assembler first pass begins:"); @@ -288,9 +302,18 @@ public ArrayList assemble(ArrayList tokenizedPro } catch (AddressErrorException e) { Token t = statement.getOriginalTokenList().get(0); errors.add(new ErrorMessage(t.getSourceProgram(), t.getSourceLine(), t - .getStartPos(), "Invalid address for text segment: " + e.getAddress())); + .getStartPos(), "Invalid address for text segment: " + statement.getAddress())); } } + + for (DataStruct ds : datalist) { + try { + Globals.memory.set(ds.address, ds.data, ds.size); + } catch (AddressErrorException e) { + if(ds.iffails != null) errors.add(ds.iffails); + } + } + // Aug. 24, 2005 Ken Vollmar // Ensure that I/O "file descriptors" are initialized for a new program run SystemIO.resetFiles(); @@ -952,15 +975,10 @@ private void storeInteger(Token token, Directives directive, ErrorList errors) { * instruction) */ else { - try { - Globals.memory.set(this.textAddress.get(), value, lengthInBytes); - } catch (AddressErrorException e) { - errors.add(new ErrorMessage(token.getSourceProgram(), - token.getSourceLine(), token.getStartPos(), "\"" - + this.textAddress.get() - + "\" is not a valid text segment address")); - return; - } + setData(this.textAddress.get(),value,lengthInBytes,new ErrorMessage(token.getSourceProgram(), + token.getSourceLine(), token.getStartPos(), "\"" + + this.textAddress.get() + + "\" is not a valid text segment address")); this.textAddress.increment(lengthInBytes); } } // end of "if integer token type" @@ -1112,27 +1130,19 @@ private void storeStrings(TokenList tokens, Directives direct, ErrorList errors) } } byte[] bytesOfChar = String.valueOf(theChar).getBytes(StandardCharsets.UTF_8); - try { - for (byte b : bytesOfChar) { - Globals.memory.set(this.dataAddress.get(), b, - DataTypes.CHAR_SIZE); - this.dataAddress.increment(DataTypes.CHAR_SIZE); - } - } catch (AddressErrorException e) { - errors.add(new ErrorMessage(token.getSourceProgram(), token - .getSourceLine(), token.getStartPos(), "\"" - + this.dataAddress.get() + "\" is not a valid data segment address")); + ErrorMessage e = new ErrorMessage(token.getSourceProgram(), token + .getSourceLine(), token.getStartPos(), "\"" + + this.dataAddress.get() + "\" is not a valid data segment address"); + for (byte b : bytesOfChar) { + setData(this.dataAddress.get(),b,DataTypes.CHAR_SIZE, e); + this.dataAddress.increment(DataTypes.CHAR_SIZE); } - } if (direct == Directives.ASCIZ || direct == Directives.STRING) { - try { - Globals.memory.set(this.dataAddress.get(), 0, DataTypes.CHAR_SIZE); - } catch (AddressErrorException e) { - errors.add(new ErrorMessage(token.getSourceProgram(), token - .getSourceLine(), token.getStartPos(), "\"" - + this.dataAddress.get() + "\" is not a valid data segment address")); - } + ErrorMessage e = new ErrorMessage(token.getSourceProgram(), token + .getSourceLine(), token.getStartPos(), "\"" + + this.dataAddress.get() + "\" is not a valid data segment address"); + setData(this.dataAddress.get(),0,DataTypes.CHAR_SIZE, e); this.dataAddress.increment(DataTypes.CHAR_SIZE); } } @@ -1160,14 +1170,10 @@ private int writeToDataSegment(int value, int lengthInBytes, Token token, ErrorL if (this.autoAlign) { this.dataAddress.set(this.alignToBoundary(this.dataAddress.get(), lengthInBytes)); } - try { - Globals.memory.set(this.dataAddress.get(), value, lengthInBytes); - } catch (AddressErrorException e) { - errors.add(new ErrorMessage(token.getSourceProgram(), token.getSourceLine(), token - .getStartPos(), "\"" + this.dataAddress.get() - + "\" is not a valid data segment address")); - return this.dataAddress.get(); - } + ErrorMessage e = new ErrorMessage(token.getSourceProgram(), token + .getSourceLine(), token.getStartPos(), "\"" + + this.dataAddress.get() + "\" is not a valid data segment address"); + setData(this.dataAddress.get(),value,lengthInBytes, e); int address = this.dataAddress.get(); this.dataAddress.increment(lengthInBytes); return address; @@ -1183,14 +1189,12 @@ private void writeDoubleToDataSegment(double value, Token token, ErrorList error if (this.autoAlign) { this.dataAddress.set(this.alignToBoundary(this.dataAddress.get(), lengthInBytes)); } - try { - Globals.memory.setDouble(this.dataAddress.get(), value); - } catch (AddressErrorException e) { - errors.add(new ErrorMessage(token.getSourceProgram(), token.getSourceLine(), token - .getStartPos(), "\"" + this.dataAddress.get() - + "\" is not a valid data segment address")); - return; - } + ErrorMessage e = new ErrorMessage(token.getSourceProgram(), token.getSourceLine(), token + .getStartPos(), "\"" + this.dataAddress.get() + + "\" is not a valid data segment address"); + long longValue = Double.doubleToLongBits(value); + setData(this.dataAddress.get(),(int)longValue, DataTypes.WORD_SIZE,e); + setData(this.dataAddress.get()+DataTypes.WORD_SIZE,(int)(longValue>>32), DataTypes.WORD_SIZE,e); this.dataAddress.increment(lengthInBytes); } @@ -1295,10 +1299,7 @@ private void resolve(SymbolTable localSymtab) { labelAddress = localSymtab.getAddressLocalOrGlobal(entry.token.getValue()); if (labelAddress != SymbolTable.NOT_FOUND) { // patch address has to be valid b/c we already stored there... - try { - Globals.memory.set(entry.patchAddress, labelAddress, entry.length); - } catch (AddressErrorException aee) { - } + setData(entry.patchAddress,labelAddress,entry.length, null); forwardReferenceList.remove(i); i--; // needed because removal shifted the remaining list indices down } diff --git a/src/rars/extras/Documentation.java b/src/rars/extras/Documentation.java index 1daef325..799f23e1 100644 --- a/src/rars/extras/Documentation.java +++ b/src/rars/extras/Documentation.java @@ -3,6 +3,7 @@ import rars.Globals; import rars.assembler.Directives; import rars.riscv.*; +import rars.riscv.hardware.Memory; import java.util.ArrayList; import java.util.Collections; @@ -17,8 +18,7 @@ public class Documentation { public static void main(String[] args){ - Globals.instructionSet = new InstructionSet(); - Globals.instructionSet.populate(); + Globals.initialize(false); System.out.println(createDirectiveMarkdown()); System.out.println(createSyscallMarkdown()); System.out.println(createInstructionMarkdown(BasicInstruction.class)); diff --git a/src/rars/riscv/hardware/Memory.java b/src/rars/riscv/hardware/Memory.java index 9301aad6..2279539f 100644 --- a/src/rars/riscv/hardware/Memory.java +++ b/src/rars/riscv/hardware/Memory.java @@ -5,12 +5,8 @@ import rars.Settings; import rars.SimulationException; import rars.riscv.Instruction; -import rars.util.Binary; -import java.util.Collection; -import java.util.Observable; -import java.util.Observer; -import java.util.Vector; +import java.util.*; /* Copyright (c) 2003-2009, Pete Sanderson and Kenneth Vollmar @@ -48,74 +44,13 @@ a copy of this software and associated documentation files (the */ public class Memory extends Observable { - - /** - * base address for (user) text segment: 0x00400000 - **/ - public static int textBaseAddress = MemoryConfigurations.getDefaultTextBaseAddress(); //0x00400000; - /** - * base address for (user) data segment: 0x10000000 - **/ - public static int dataSegmentBaseAddress = MemoryConfigurations.getDefaultDataSegmentBaseAddress(); //0x10000000; - /** - * base address for .extern directive: 0x10000000 - **/ - public static int externBaseAddress = MemoryConfigurations.getDefaultExternBaseAddress(); //0x10000000; - /** - * base address for storing globals - **/ - public static int globalPointer = MemoryConfigurations.getDefaultGlobalPointer(); //0x10008000; - /** - * base address for storage of non-global static data in data segment: 0x10010000 (from SPIM) - **/ - public static int dataBaseAddress = MemoryConfigurations.getDefaultDataBaseAddress(); //0x10010000; // from SPIM not MIPS - /** - * base address for heap: 0x10040000 (I think from SPIM not MIPS) - **/ - public static int heapBaseAddress = MemoryConfigurations.getDefaultHeapBaseAddress(); //0x10040000; // I think from SPIM not MIPS - /** - * starting address for stack: 0x7fffeffc (this is from SPIM not MIPS) - **/ - public static int stackPointer = MemoryConfigurations.getDefaultStackPointer(); //0x7fffeffc; - /** - * base address for stack: 0x7ffffffc (this is mine - start of highest word below kernel space) - **/ - public static int stackBaseAddress = MemoryConfigurations.getDefaultStackBaseAddress(); //0x7ffffffc; - /** - * highest address accessible in user (not kernel) mode. - **/ - public static int userHighAddress = MemoryConfigurations.getDefaultUserHighAddress(); //0x7fffffff; - /** - * kernel boundary. Only OS can access this or higher address - **/ - public static int kernelBaseAddress = MemoryConfigurations.getDefaultKernelBaseAddress(); //0x80000000; - /** - * starting address for memory mapped I/O: 0xffff0000 (-65536) - **/ - public static int memoryMapBaseAddress = MemoryConfigurations.getDefaultMemoryMapBaseAddress(); //0xffff0000; - /** - * highest address acessible in kernel mode. - **/ - public static int kernelHighAddress = MemoryConfigurations.getDefaultKernelHighAddress(); //0xffffffff; - /** * Word length in bytes. **/ // NOTE: Much of the code is hardwired for 4 byte words. Refactoring this is low priority. public static final int WORD_LENGTH_BYTES = 4; - // TODO: remove this as RISCV is little endian and it is only used in like one spot - /** - * Constant representing byte order of each memory word. Little-endian means lowest - * numbered byte is right most [3][2][1][0]. - */ - public static final boolean LITTLE_ENDIAN = true; - /** - * Current setting for endian (default LITTLE_ENDIAN) - **/ - private static boolean byteOrder = LITTLE_ENDIAN; - - public static int heapAddress; + public static MemoryConfiguration configuration; // Memory will maintain a collection of observables. Each one is associated // with a specific memory address or address range, and each will have at least @@ -202,15 +137,6 @@ public class Memory extends Observable { // Set "top" address boundary to go with each "base" address. This determines permissable // address range for user program. Currently limit is 4MB, or 1024 * 1024 * 4 bytes based // on the table structures described above (except memory mapped IO, limited to 64KB by range). - - public static int dataSegmentLimitAddress = dataSegmentBaseAddress + - BLOCK_LENGTH_WORDS * BLOCK_TABLE_LENGTH * WORD_LENGTH_BYTES; - public static int textLimitAddress = textBaseAddress + - TEXT_BLOCK_LENGTH_WORDS * TEXT_BLOCK_TABLE_LENGTH * WORD_LENGTH_BYTES; - public static int stackLimitAddress = stackBaseAddress - - BLOCK_LENGTH_WORDS * BLOCK_TABLE_LENGTH * WORD_LENGTH_BYTES; - public static int memoryMapLimitAddress = memoryMapBaseAddress + - BLOCK_LENGTH_WORDS * MMIO_TABLE_LENGTH * WORD_LENGTH_BYTES; // This will be a Singleton class, only one instance is ever created. Since I know the // Memory object is always needed, I'll go ahead and create it at the time of class loading. // (greedy rather than lazy instantiation). The constructor is private and getInstance() @@ -219,6 +145,9 @@ public class Memory extends Observable { private static Memory uniqueMemoryInstance = new Memory(); + { + setConfiguration(); + } /* * Private constructor for Memory. Separate data structures for text and data segments. **/ @@ -297,34 +226,23 @@ public void clear() { */ public static void setConfiguration() { - textBaseAddress = MemoryConfigurations.getCurrentConfiguration().getTextBaseAddress(); //0x00400000; - dataSegmentBaseAddress = MemoryConfigurations.getCurrentConfiguration().getDataSegmentBaseAddress(); //0x10000000; - externBaseAddress = MemoryConfigurations.getCurrentConfiguration().getExternBaseAddress(); //0x10000000; - globalPointer = MemoryConfigurations.getCurrentConfiguration().getGlobalPointer(); //0x10008000; - dataBaseAddress = MemoryConfigurations.getCurrentConfiguration().getDataBaseAddress(); //0x10010000; // from SPIM not MIPS - heapBaseAddress = MemoryConfigurations.getCurrentConfiguration().getHeapBaseAddress(); //0x10040000; // I think from SPIM not MIPS - stackPointer = MemoryConfigurations.getCurrentConfiguration().getStackPointer(); //0x7fffeffc; - stackBaseAddress = MemoryConfigurations.getCurrentConfiguration().getStackBaseAddress(); //0x7ffffffc; - userHighAddress = MemoryConfigurations.getCurrentConfiguration().getUserHighAddress(); //0x7fffffff; - kernelBaseAddress = MemoryConfigurations.getCurrentConfiguration().getKernelBaseAddress(); //0x80000000; - memoryMapBaseAddress = MemoryConfigurations.getCurrentConfiguration().getMemoryMapBaseAddress(); //0xffff0000; - kernelHighAddress = MemoryConfigurations.getCurrentConfiguration().getKernelHighAddress(); //0xffffffff; - dataSegmentLimitAddress = Math.min(MemoryConfigurations.getCurrentConfiguration().getDataSegmentLimitAddress(), - dataSegmentBaseAddress + - BLOCK_LENGTH_WORDS * BLOCK_TABLE_LENGTH * WORD_LENGTH_BYTES); - textLimitAddress = Math.min(MemoryConfigurations.getCurrentConfiguration().getTextLimitAddress(), - textBaseAddress + - TEXT_BLOCK_LENGTH_WORDS * TEXT_BLOCK_TABLE_LENGTH * WORD_LENGTH_BYTES); - stackLimitAddress = Math.max(MemoryConfigurations.getCurrentConfiguration().getStackLimitAddress(), - stackBaseAddress - - BLOCK_LENGTH_WORDS * BLOCK_TABLE_LENGTH * WORD_LENGTH_BYTES); - memoryMapLimitAddress = Math.min(MemoryConfigurations.getCurrentConfiguration().getMemoryMapLimitAddress(), - memoryMapBaseAddress + - BLOCK_LENGTH_WORDS * MMIO_TABLE_LENGTH * WORD_LENGTH_BYTES); + MemoryConfiguration t = MemoryConfigurations.getCurrentConfiguration(); + HashMap sections = new HashMap<>(); + // Default configuration comes from SPIM + sections.put(".text", t.text.limit(TEXT_BLOCK_LENGTH_WORDS * TEXT_BLOCK_TABLE_LENGTH * WORD_LENGTH_BYTES)); + sections.put(".data", t.data.limit(BLOCK_LENGTH_WORDS * BLOCK_TABLE_LENGTH * WORD_LENGTH_BYTES)); + sections.put("heap", t.heap); + sections.put("stack", t.stack.limitReverse(BLOCK_LENGTH_WORDS * BLOCK_TABLE_LENGTH * WORD_LENGTH_BYTES-1)); + sections.put("mmio", t.mmio.limit(BLOCK_LENGTH_WORDS * MMIO_TABLE_LENGTH * WORD_LENGTH_BYTES)); + configuration = new MemoryConfiguration(t.getConfigurationIdentifier(),t.getConfigurationName(), sections,t.gp_offset,t.extern_size); + + + RegisterFile.getRegister("sp").changeResetValue(configuration.getStackBaseAddress()); + RegisterFile.getRegister("gp").changeResetValue(configuration.getGlobalPointer()); } private void initialize() { - heapAddress = heapBaseAddress; + heapAddress = configuration.getHeapBaseAddress(); textBlockTable = new ProgramStatement[TEXT_BLOCK_TABLE_LENGTH][]; dataBlockTable = new int[BLOCK_TABLE_LENGTH][]; // array of null int[] references stackBlockTable = new int[BLOCK_TABLE_LENGTH][]; @@ -332,6 +250,8 @@ private void initialize() { System.gc(); // call garbage collector on any Table memory just deallocated. } + + private int heapAddress; // TODO: add some heap managment so programs can malloc and free /** * Returns the next available word-aligned heap address. There is no recycling and @@ -350,11 +270,12 @@ public int allocateBytesFromHeap(int numBytes) throws IllegalArgumentException { if (newHeapAddress % 4 != 0) { newHeapAddress = newHeapAddress + (4 - newHeapAddress % 4); // next higher multiple of 4 } - if (newHeapAddress >= dataSegmentLimitAddress) { + if (newHeapAddress >= configuration.heap.high) { throw new IllegalArgumentException("request (" + numBytes + ") exceeds available heap storage"); } heapAddress = newHeapAddress; return result; + } /* ******************************* THE SETTER METHODS ******************************/ @@ -378,16 +299,16 @@ public int set(int address, int value, int length) throws AddressErrorException int oldValue = 0; if (Globals.debug) System.out.println("memory[" + address + "] set to " + value + "(" + length + " bytes)"); int relativeByteAddress; - if (inDataSegment(address)) { + if (configuration.data.contains(address,length)) { // in data segment. Will write one byte at a time, w/o regard to boundaries. - relativeByteAddress = address - dataSegmentBaseAddress; // relative to data segment start, in bytes + relativeByteAddress = address - configuration.data.low; // relative to data segment start, in bytes oldValue = storeBytesInTable(dataBlockTable, relativeByteAddress, length, value); - } else if (address > stackLimitAddress && address <= stackBaseAddress) { + } else if (configuration.stack.contains(address,length)) { // in stack. Handle similarly to data segment write, except relative byte // address calculated "backward" because stack addresses grow down from base. - relativeByteAddress = stackBaseAddress - address; + relativeByteAddress = configuration.stack.high - address; oldValue = storeBytesInTable(stackBlockTable, relativeByteAddress, length, value); - } else if (inTextSegment(address)) { + } else if (configuration.text.contains(address,length)) { // Burch Mod (Jan 2013): replace throw with call to setStatement // DPS adaptation 5-Jul-2013: either throw or call, depending on setting @@ -416,9 +337,9 @@ public int set(int address, int value, int length) throws AddressErrorException "Cannot write directly to text segment!", SimulationException.STORE_ACCESS_FAULT, address); } - } else if (address >= memoryMapBaseAddress && address < memoryMapLimitAddress) { + } else if (configuration.mmio.contains(address,length)) { // memory mapped I/O. - relativeByteAddress = address - memoryMapBaseAddress; + relativeByteAddress = address - configuration.mmio.low; oldValue = storeBytesInTable(memoryMapBlockTable, relativeByteAddress, length, value); } else { // falls outside addressing range @@ -442,45 +363,7 @@ public int set(int address, int value, int length) throws AddressErrorException * @throws AddressErrorException If address is not on word boundary. **/ public int setRawWord(int address, int value) throws AddressErrorException { - int relative, oldValue = 0; - checkStoreWordAligned(address); - if (inDataSegment(address)) { - // in data segment - relative = (address - dataSegmentBaseAddress) >> 2; // convert byte address to words - oldValue = storeWordInTable(dataBlockTable, relative, value); - } else if (address > stackLimitAddress && address <= stackBaseAddress) { - // in stack. Handle similarly to data segment write, except relative - // address calculated "backward" because stack addresses grow down from base. - relative = (stackBaseAddress - address) >> 2; // convert byte address to words - oldValue = storeWordInTable(stackBlockTable, relative, value); - } else if (inTextSegment(address)) { - // Burch Mod (Jan 2013): replace throw with call to setStatement - // DPS adaptation 5-Jul-2013: either throw or call, depending on setting - if (Globals.getSettings().getBooleanSetting(Settings.Bool.SELF_MODIFYING_CODE_ENABLED)) { - ProgramStatement oldStatement = getStatementNoNotify(address); - if (oldStatement != null) { - oldValue = oldStatement.getBinaryStatement(); - } - setStatement(address, new ProgramStatement(value, address)); - } else { - throw new AddressErrorException( - "Cannot write directly to text segment!", - SimulationException.STORE_ACCESS_FAULT, address); - } - } else if (address >= memoryMapBaseAddress && address < memoryMapLimitAddress) { - // memory mapped I/O. - relative = (address - memoryMapBaseAddress) >> 2; // convert byte address to word - oldValue = storeWordInTable(memoryMapBlockTable, relative, value); - } else { - // falls outside addressing range - throw new AddressErrorException("store address out of range ", - SimulationException.STORE_ACCESS_FAULT, address); - } - notifyAnyObservers(AccessNotice.WRITE, address, WORD_LENGTH_BYTES, value); - if (Globals.getSettings().getBackSteppingEnabled()) { - Globals.program.getBackStepper().addMemoryRestoreRawWord(address, oldValue); - } - return oldValue; + return setWord(address,Integer.reverseBytes(value)); } /////////////////////////////////////////////////////////////////////////////////////// @@ -541,9 +424,7 @@ public int setByte(int address, int value) throws AddressErrorException { /** - * Writes 64 bit doubleword value starting at specified Memory address. Note that - * high-order 32 bits are stored in higher (second) memory word regardless - * of "endianness". + * Writes 64 bit doubleword value starting at specified Memory address. * * @param address Starting address of Memory address to be set. * @param value Value to be stored at that address. @@ -562,9 +443,7 @@ public long setDoubleWord(int address, long value) throws AddressErrorException /////////////////////////////////////////////////////////////////////////////////////// /** - * Writes 64 bit double value starting at specified Memory address. Note that - * high-order 32 bits are stored in higher (second) memory word regardless - * of "endianness". + * Writes 64 bit double value starting at specified Memory address. * * @param address Starting address of Memory address to be set. * @param value Value to be stored at that address. @@ -597,7 +476,7 @@ public void setStatement(int address, ProgramStatement statement) throws Address SimulationException.STORE_ACCESS_FAULT, address); } if (Globals.debug) System.out.println("memory[" + address + "] set to " + statement.getBinaryStatement()); - storeProgramStatement(address, statement, textBaseAddress, textBlockTable); + storeProgramStatement(address, statement, configuration.text.low, textBlockTable); } @@ -623,19 +502,19 @@ public int get(int address, int length) throws AddressErrorException { private int get(int address, int length, boolean notify) throws AddressErrorException { int value = 0; int relativeByteAddress; - if (inDataSegment(address)) { + if (configuration.data.contains(address,length)) { // in data segment. Will read one byte at a time, w/o regard to boundaries. - relativeByteAddress = address - dataSegmentBaseAddress; // relative to data segment start, in bytes + relativeByteAddress = address - configuration.data.low; // relative to data segment start, in bytes value = fetchBytesFromTable(dataBlockTable, relativeByteAddress, length); - } else if (address > stackLimitAddress && address <= stackBaseAddress) { + } else if (configuration.stack.contains(address,length)) { // in stack. Similar to data, except relative address computed "backward" - relativeByteAddress = stackBaseAddress - address; + relativeByteAddress = configuration.stack.high - address; value = fetchBytesFromTable(stackBlockTable, relativeByteAddress, length); - } else if (address >= memoryMapBaseAddress && address < memoryMapLimitAddress) { + } else if (configuration.mmio.contains(address,length)) { // memory mapped I/O. - relativeByteAddress = address - memoryMapBaseAddress; + relativeByteAddress = address - configuration.mmio.low; value = fetchBytesFromTable(memoryMapBlockTable, relativeByteAddress, length); - } else if (inTextSegment(address)) { + } else if (configuration.text.contains(address,length)) { // Burch Mod (Jan 2013): replace throw with calls to getStatementNoNotify & getBinaryStatement // DPS adaptation 5-Jul-2013: either throw or call, depending on setting if (Globals.getSettings().getBooleanSetting(Settings.Bool.SELF_MODIFYING_CODE_ENABLED)) { @@ -682,39 +561,7 @@ private int get(int address, int length, boolean notify) throws AddressErrorExce // Doing so would be detrimental to simulation runtime performance, so // I decided to keep the duplicate logic. public int getRawWord(int address) throws AddressErrorException { - int value = 0; - int relative; - checkLoadWordAligned(address); - if (inDataSegment(address)) { - // in data segment - relative = (address - dataSegmentBaseAddress) >> 2; // convert byte address to words - value = fetchWordFromTable(dataBlockTable, relative); - } else if (address > stackLimitAddress && address <= stackBaseAddress) { - // in stack. Similar to data, except relative address computed "backward" - relative = (stackBaseAddress - address) >> 2; // convert byte address to words - value = fetchWordFromTable(stackBlockTable, relative); - } else if (address >= memoryMapBaseAddress && address < memoryMapLimitAddress) { - // memory mapped I/O. - relative = (address - memoryMapBaseAddress) >> 2; - value = fetchWordFromTable(memoryMapBlockTable, relative); - } else if (inTextSegment(address)) { - // Burch Mod (Jan 2013): replace throw with calls to getStatementNoNotify & getBinaryStatement - // DPS adaptation 5-Jul-2013: either throw or call, depending on setting - if (Globals.getSettings().getBooleanSetting(Settings.Bool.SELF_MODIFYING_CODE_ENABLED)) { - ProgramStatement stmt = getStatementNoNotify(address); - value = stmt == null ? 0 : stmt.getBinaryStatement(); - } else { - throw new AddressErrorException( - "Cannot read directly from text segment!", - SimulationException.LOAD_ACCESS_FAULT, address); - } - } else { - // falls outside addressing range - throw new AddressErrorException("address out of range ", - SimulationException.LOAD_ACCESS_FAULT, address); - } - notifyAnyObservers(AccessNotice.READ, address, Memory.WORD_LENGTH_BYTES, value); - return value; + return Integer.reverseBytes(getWord(address)); } ///////////////////////////////////////////////////////////////////////// @@ -743,15 +590,15 @@ public Integer getRawWordOrNull(int address) throws AddressErrorException { Integer value = null; int relative; checkLoadWordAligned(address); - if (inDataSegment(address)) { + if (configuration.data.contains(address,4)) { // in data segment - relative = (address - dataSegmentBaseAddress) >> 2; // convert byte address to words + relative = (address - configuration.data.low) >> 2; // convert byte address to words value = fetchWordOrNullFromTable(dataBlockTable, relative); - } else if (address > stackLimitAddress && address <= stackBaseAddress) { + } else if (configuration.stack.contains(address,4)) { // in stack. Similar to data, except relative address computed "backward" - relative = (stackBaseAddress - address) >> 2; // convert byte address to words + relative = (configuration.stack.high - address) >> 2; // convert byte address to words value = fetchWordOrNullFromTable(stackBlockTable, relative); - } else if (inTextSegment(address)) { + } else if (configuration.text.contains(address,4)) { try { value = (getStatementNoNotify(address) == null) ? null : getStatementNoNotify(address).getBinaryStatement(); } catch (AddressErrorException aee) { @@ -891,7 +738,7 @@ private ProgramStatement getStatement(int address, boolean notify) throws Addres SimulationException.LOAD_ACCESS_FAULT, address); } if (inTextSegment(address)) - return readProgramStatement(address, textBaseAddress, textBlockTable, notify); + return readProgramStatement(address, configuration.text.low, textBlockTable, notify); else return new ProgramStatement(get(address, WORD_LENGTH_BYTES), address); } @@ -937,7 +784,7 @@ public static boolean doublewordAligned(int address) { /** * Handy little utility to find out if given address is in the text - * segment (starts at Memory.textBaseAddress). + * segment (starts at Memory.configuration.getTextBaseAddress()). * Note that RARS does not implement the entire text segment space, * but it does implement enough for hundreds of thousands of lines * of code. @@ -947,31 +794,31 @@ public static boolean doublewordAligned(int address) { * false otherwise. */ public static boolean inTextSegment(int address) { - return address >= textBaseAddress && address < textLimitAddress; + return configuration.text.contains(address,4); } /** * Handy little utility to find out if given address is in RARS data - * segment (starts at Memory.dataSegmentBaseAddress). + * segment (starts at Memory.configuration.getDataSegmentBaseAddress()). * * @param address integer memory address * @return true if that address is within RARS-defined data segment, * false otherwise. */ public static boolean inDataSegment(int address) { - return address >= dataSegmentBaseAddress && address < dataSegmentLimitAddress; + return configuration.data.contains(address,4); } /** * Handy little utility to find out if given address is in the Memory Map area - * starts at Memory.memoryMapBaseAddress, range 0xffff0000 to 0xffffffff. + * starts at Memory.configuration.getMemoryMapBaseAddress(), range 0xffff0000 to 0xffffffff. * * @param address integer memory address * @return true if that address is within RARS-defined memory map (MMIO) area, * false otherwise. */ public static boolean inMemoryMapSegment(int address) { - return address >= memoryMapBaseAddress && address < kernelHighAddress; + return configuration.mmio.contains(address,4); } @@ -1210,7 +1057,7 @@ private synchronized int storeOrFetchBytesInTable(int[][] blockTable, else return 0; } - if (byteOrder == LITTLE_ENDIAN) bytePositionInMemory = 3 - bytePositionInMemory; + bytePositionInMemory = 3 - bytePositionInMemory; if (op == STORE) { oldValue = replaceByte(blockTable[block][offset], bytePositionInMemory, oldValue, bytePositionInValue); diff --git a/src/rars/riscv/hardware/MemoryConfiguration.java b/src/rars/riscv/hardware/MemoryConfiguration.java index 8cb46eb9..3b0173fd 100644 --- a/src/rars/riscv/hardware/MemoryConfiguration.java +++ b/src/rars/riscv/hardware/MemoryConfiguration.java @@ -28,6 +28,11 @@ a copy of this software and associated documentation files (the (MIT license, http://www.opensource.org/licenses/mit-license.html) */ +import rars.util.Binary; + +import java.util.HashMap; +import java.util.Map; + /** * Models the memory configuration for the simulated MIPS machine. * "configuration" refers to the starting memory addresses for @@ -41,19 +46,31 @@ a copy of this software and associated documentation files (the public class MemoryConfiguration { - // TODO: remove kernel mode maybe? - // TODO: move away from a multi-array approach to array of ranges approach // Identifier is used for saving setting; name is used for display private String configurationIdentifier, configurationName; - private String[] configurationItemNames; - private int[] configurationItemValues; + public final Range text, data, heap, stack, mmio, total; + public final Map sections; + public final int gp_offset, extern_size; + public final boolean builtin; - public MemoryConfiguration(String ident, String name, String[] items, int[] values) { + public MemoryConfiguration(String ident, String name, Map sections, int gp_offset, int extern_size){ + this(ident, name, sections, gp_offset,extern_size,true); + } + public MemoryConfiguration(String ident, String name, Map sections, int gp_offset, int extern_size, boolean builtin){ this.configurationIdentifier = ident; this.configurationName = name; - this.configurationItemNames = items; - this.configurationItemValues = values; + this.builtin = builtin; + text = sections.get(".text"); + data = sections.get(".data"); + heap = sections.get("heap"); + stack = sections.get("stack"); + mmio = sections.get("mmio"); + total = sections.values().stream().reduce(text, Range::combine); + this.sections = new HashMap<>(); + this.sections.putAll(sections); + this.gp_offset = gp_offset; + this.extern_size = extern_size; } public String getConfigurationIdentifier() { @@ -64,76 +81,57 @@ public String getConfigurationName() { return configurationName; } - public int[] getConfigurationItemValues() { - return configurationItemValues; - } - - public String[] getConfigurationItemNames() { - return configurationItemNames; - } - public int getTextBaseAddress() { - return configurationItemValues[0]; + return text.low; } public int getDataSegmentBaseAddress() { - return configurationItemValues[1]; + return data.low; } public int getExternBaseAddress() { - return configurationItemValues[2]; + return data.low; } public int getGlobalPointer() { - return configurationItemValues[3]; + return data.low+gp_offset; } public int getDataBaseAddress() { - return configurationItemValues[4]; + return data.low+extern_size; } public int getHeapBaseAddress() { - return configurationItemValues[5]; - } - - public int getStackPointer() { - return configurationItemValues[6]; + return heap.low; } public int getStackBaseAddress() { - return configurationItemValues[7]; - } - - public int getUserHighAddress() { - return configurationItemValues[8]; - } - - public int getKernelBaseAddress() { - return configurationItemValues[9]; + return stack.high; } public int getMemoryMapBaseAddress() { - return configurationItemValues[10]; - } - - public int getKernelHighAddress() { - return configurationItemValues[11]; + return mmio.low; } public int getDataSegmentLimitAddress() { - return configurationItemValues[12]; + return heap.high; } public int getTextLimitAddress() { - return configurationItemValues[13]; + return text.high; + } + + public String toPropertiesString(){ + StringBuilder sb = new StringBuilder(); + for(Map.Entry entry : sections.entrySet()){ + sb.append(entry.getKey()).append(" = "); + sb.append(Binary.intToHexString(entry.getValue().low)).append('-'); + sb.append(Binary.intToHexString(entry.getValue().high)).append('\n'); + } + sb.append("name = ").append(configurationName).append('\n'); + sb.append("ident = ").append(configurationIdentifier).append('\n'); + sb.append("gp_offset = ").append(Binary.intToHexString(gp_offset)).append('\n'); + sb.append("extern_offset = ").append(Binary.intToHexString(extern_size)).append('\n'); + return sb.toString(); } - - public int getStackLimitAddress() { - return configurationItemValues[14]; - } - - public int getMemoryMapLimitAddress() { - return configurationItemValues[15]; - } - } \ No newline at end of file diff --git a/src/rars/riscv/hardware/MemoryConfigurations.java b/src/rars/riscv/hardware/MemoryConfigurations.java index 22a1d4cd..7bedb4d6 100644 --- a/src/rars/riscv/hardware/MemoryConfigurations.java +++ b/src/rars/riscv/hardware/MemoryConfigurations.java @@ -1,9 +1,9 @@ package rars.riscv.hardware; import rars.Globals; - -import java.util.ArrayList; -import java.util.Iterator; +import rars.util.Binary; +import java.io.InputStream; +import java.util.*; /* Copyright (c) 2003-2009, Pete Sanderson and Kenneth Vollmar @@ -49,114 +49,42 @@ public class MemoryConfigurations { private static MemoryConfiguration defaultConfiguration; private static MemoryConfiguration currentConfiguration; - // Be careful, these arrays are parallel and position-sensitive. - // The getters in this and in MemoryConfiguration depend on this - // sequence. Should be refactored... The order comes from the - // original listed order in Memory.java, where most of these were - // "final" until Mars 3.7 and changeable memory configurations. - private static final String[] configurationItemNames = { - ".text base address", - "data segment base address", - ".extern base address", - "global pointer (gp)", - ".data base address", - "heap base address", - "stack pointer (sp)", - "stack base address", - "user space high address", - "kernel space base address", - "MMIO base address", - "kernel space high address", - "data segment limit address", - "text limit address", - "stack limit address", - "memory map limit address" - }; - - // Default configuration comes from SPIM - private static int[] defaultConfigurationItemValues = { - 0x00400000, // .text Base Address - 0x10000000, // Data Segment base address - 0x10000000, // .extern Base Address - 0x10008000, // Global Pointer $gp) - 0x10010000, // .data base Address - 0x10040000, // heap base address - 0x7fffeffc, // stack pointer $sp (from SPIM not MIPS) - 0x7ffffffc, // stack base address - 0x7fffffff, // highest address in user space - 0x80000000, // lowest address in kernel space - 0xffff0000, // MMIO base address - 0xffffffff, // highest address in kernel (and memory) - 0x7fffffff, // data segment limit address - 0x0ffffffc, // text limit address - 0x10040000, // stack limit address - 0xffffffff // memory map limit address - }; - - // Compact allows 16 bit addressing, data segment starts at 0 - private static int[] dataBasedCompactConfigurationItemValues = { - 0x00003000, // .text Base Address - 0x00000000, // Data Segment base address - 0x00001000, // .extern Base Address - 0x00001800, // Global Pointer $gp) - 0x00000000, // .data base Address - 0x00002000, // heap base address - 0x00002ffc, // stack pointer $sp - 0x00002ffc, // stack base address - 0x00003fff, // highest address in user space - 0x00004000, // lowest address in kernel space - 0x00007f00, // MMIO base address - 0x00007fff, // highest address in kernel (and memory) - 0x00002fff, // data segment limit address - 0x00003ffc, // text limit address - 0x00002000, // stack limit address - 0x00007fff // memory map limit address - }; - - // Compact allows 16 bit addressing, text segment starts at 0 - private static int[] textBasedCompactConfigurationItemValues = { - 0x00000000, // .text Base Address - 0x00001000, // Data Segment base address - 0x00001000, // .extern Base Address - 0x00001800, // Global Pointer $gp) - 0x00002000, // .data base Address - 0x00003000, // heap base address - 0x00003ffc, // stack pointer $sp - 0x00003ffc, // stack base address - 0x00003fff, // highest address in user space - 0x00004000, // lowest address in kernel space - 0x00007f00, // MMIO base address - 0x00007fff, // highest address in kernel (and memory) - 0x00003fff, // data segment limit address - 0x00000ffc, // text limit address - 0x00003000, // stack limit address - 0x00007fff // memory map limit address - }; - - public MemoryConfigurations() { } - public static void buildConfigurationCollection() { if (configurations == null) { configurations = new ArrayList<>(); - configurations.add(new MemoryConfiguration("Default", "Default", configurationItemNames, defaultConfigurationItemValues)); - configurations.add(new MemoryConfiguration("CompactDataAtZero", "Compact, Data at Address 0", configurationItemNames, dataBasedCompactConfigurationItemValues)); - configurations.add(new MemoryConfiguration("CompactTextAtZero", "Compact, Text at Address 0", configurationItemNames, textBasedCompactConfigurationItemValues)); + HashMap sections = new HashMap<>(); + // Default configuration comes from SPIM + sections.put(".text", new Range( 0x400000,0x10000000)); + sections.put(".data", new Range(0x10000000,0x10040000)); + sections.put("heap", new Range(0x10040000,0x30000000)); + sections.put("stack", new Range(0x60000000,0x80000000)); + sections.put("mmio", new Range(0xffff0000,0xffffffff)); + configurations.add(new MemoryConfiguration("Default","Default", sections,0x8000,0x10000)); + + sections = new HashMap<>(); + // Compact allows 16 bit addressing, data segment starts at 0 + sections.put(".text", new Range(0x3000,0x4000)); + sections.put(".data", new Range(0x0000,0x2000)); + sections.put("heap", new Range(0x2000,0x2800)); //Heap and stack split in half (ideally they should overlap) + sections.put("stack", new Range(0x2800,0x3000)); + sections.put("mmio", new Range(0x7f00,0x8000)); + configurations.add(new MemoryConfiguration("CompactDataAtZero", "Compact, Data at Address 0", sections,0x1800,0x1000)); + + sections = new HashMap<>(); + // Compact allows 16 bit addressing, text segment starts at 0 + sections.put(".text", new Range(0x0000,0x1000)); + sections.put(".data", new Range(0x1000,0x3000)); + sections.put("heap", new Range(0x3000,0x3800)); //Heap and stack split in half (ideally they should overlap) + sections.put("stack", new Range(0x3800,0x4000)); + sections.put("mmio", new Range(0x7f00,0x8000)); + configurations.add(new MemoryConfiguration("CompactTextAtZero", "Compact, Text at Address 0", sections,0x800,0x1000)); + defaultConfiguration = configurations.get(0); currentConfiguration = defaultConfiguration; - // Get current config from settings - //String currentConfigurationIdentifier = Globals.getSettings().getMemoryConfiguration(); - setCurrentConfiguration(getConfigurationByName(Globals.getSettings().getMemoryConfiguration())); - // Iterator configurationsIterator = getConfigurationsIterator(); - // while (configurationsIterator.hasNext()) { - // MemoryConfiguration config = (MemoryConfiguration)configurationsIterator.next(); - // if (currentConfigurationIdentifier.equals(config.getConfigurationIdentifier())) { - // setCurrentConfiguration(config); - // } - // } } } @@ -168,6 +96,43 @@ public static Iterator getConfigurationsIterator() { } + public static void addNewConfig(MemoryConfiguration mc){ + configurations.add(mc); + } + public static MemoryConfiguration loadNewConfig(InputStream is) { + Properties f = new Properties(); + try { + f.load(is); + } catch(Exception e){ + return null; + } + Map ranges = new HashMap<>(); + for(String name : f.stringPropertyNames()) { + String value = f.getProperty(name); + if (!value.contains("-")) continue; + String[] ends = value.split("-"); + if (ends.length != 2) continue; + Integer first = Binary.stringToIntFast(ends[0]), second = Binary.stringToIntFast(ends[1]); + if (first == null || second == null) continue; + if (Integer.compareUnsigned(first, second) <= 0) { + ranges.put(name, new Range(first, second)); + } else { + ranges.put(name, new Range(second, first)); + } + } + + String gp = f.getProperty("gp_offset"), extern = f.getProperty("extern_offset"); + if(gp == null || extern == null) return null; + + + Integer gpint = Binary.stringToIntFast(gp), externint = Binary.stringToIntFast(extern); + if(gpint == null || externint == null) return null; + + String ident = f.getProperty("ident"), name = f.getProperty("name"); + if(ident == null || name == null) return null; + return new MemoryConfiguration(ident,name,ranges,gpint,externint,false); + } + public static MemoryConfiguration getConfigurationByName(String name) { Iterator configurationsIterator = getConfigurationsIterator(); while (configurationsIterator.hasNext()) { @@ -201,7 +166,7 @@ public static boolean setCurrentConfiguration(MemoryConfiguration config) { currentConfiguration = config; Globals.memory.clear(); RegisterFile.getRegister("gp").changeResetValue(config.getGlobalPointer()); - RegisterFile.getRegister("sp").changeResetValue(config.getStackPointer()); + RegisterFile.getRegister("sp").changeResetValue(config.getStackBaseAddress()); RegisterFile.getProgramCounterRegister().changeResetValue(config.getTextBaseAddress()); RegisterFile.initializeProgramCounter(config.getTextBaseAddress()); RegisterFile.resetRegisters(); @@ -210,73 +175,4 @@ public static boolean setCurrentConfiguration(MemoryConfiguration config) { return false; } } - - - //// Use these to intialize Memory static variables at launch - - public static int getDefaultTextBaseAddress() { - return defaultConfigurationItemValues[0]; - } - - public static int getDefaultDataSegmentBaseAddress() { - return defaultConfigurationItemValues[1]; - } - - public static int getDefaultExternBaseAddress() { - return defaultConfigurationItemValues[2]; - } - - public static int getDefaultGlobalPointer() { - return defaultConfigurationItemValues[3]; - } - - public static int getDefaultDataBaseAddress() { - return defaultConfigurationItemValues[4]; - } - - public static int getDefaultHeapBaseAddress() { - return defaultConfigurationItemValues[5]; - } - - public static int getDefaultStackPointer() { - return defaultConfigurationItemValues[6]; - } - - public static int getDefaultStackBaseAddress() { - return defaultConfigurationItemValues[7]; - } - - public static int getDefaultUserHighAddress() { - return defaultConfigurationItemValues[8]; - } - - public static int getDefaultKernelBaseAddress() { - return defaultConfigurationItemValues[9]; - } - - public static int getDefaultMemoryMapBaseAddress() { - return defaultConfigurationItemValues[10]; - } - - public static int getDefaultKernelHighAddress() { - return defaultConfigurationItemValues[11]; - } - - public int getDefaultDataSegmentLimitAddress() { - return defaultConfigurationItemValues[12]; - } - - public int getDefaultTextLimitAddress() { - return defaultConfigurationItemValues[13]; - } - - public int getDefaultStackLimitAddress() { - return defaultConfigurationItemValues[14]; - } - - public int getMemoryMapLimitAddress() { - return defaultConfigurationItemValues[15]; - } - - } \ No newline at end of file diff --git a/src/rars/riscv/hardware/Range.java b/src/rars/riscv/hardware/Range.java new file mode 100644 index 00000000..f5f850d0 --- /dev/null +++ b/src/rars/riscv/hardware/Range.java @@ -0,0 +1,32 @@ +package rars.riscv.hardware; + +public class Range { + public final int high, low; + public Range(int low, int high){ + if(Integer.compareUnsigned(low,high) > 0) throw new IllegalArgumentException(); + this.high = high; + this.low = low; + } + public boolean contains(int ptr, int size){ + return Integer.compareUnsigned(low,ptr) <= 0 && 0 <= Integer.compareUnsigned(high,ptr+size); + } + public Range combine(Range other){ + int low = (Integer.compareUnsigned(this.low,other.low) < 0) ?this.low:other.low; + int high = (Integer.compareUnsigned(this.high,other.high) > 0) ?this.high:other.high; + return new Range(low,high); + } + public Range limit(int size){ + int tmp = low + size; + if(Integer.compareUnsigned(tmp,high) < 0 && Integer.compareUnsigned(tmp,low) > 0){ + return new Range(low,tmp); + } + return this; + } + public Range limitReverse(int size){ + int tmp = high - size; + if(Integer.compareUnsigned(tmp,low) > 0 && Integer.compareUnsigned(tmp,high) < 0){ + return new Range(tmp,high); + } + return this; + } +} \ No newline at end of file diff --git a/src/rars/riscv/hardware/RegisterFile.java b/src/rars/riscv/hardware/RegisterFile.java index 0f4f7e8c..54d38bbe 100644 --- a/src/rars/riscv/hardware/RegisterFile.java +++ b/src/rars/riscv/hardware/RegisterFile.java @@ -48,8 +48,8 @@ public class RegisterFile { public static final int STACK_POINTER_REGISTER = 2; private static final RegisterBlock instance = new RegisterBlock('x', new Register[]{ new Register("zero", 0, 0), new Register("ra", 1, 0), - new Register("sp", STACK_POINTER_REGISTER, Memory.stackPointer), - new Register("gp", GLOBAL_POINTER_REGISTER, Memory.globalPointer), + new Register("sp", STACK_POINTER_REGISTER, Memory.configuration.getStackBaseAddress()), + new Register("gp", GLOBAL_POINTER_REGISTER, Memory.configuration.getGlobalPointer()), new Register("tp", 4, 0), new Register("t0", 5, 0), new Register("t1", 6, 0), new Register("t2", 7, 0), new Register("s0", 8, 0), new Register("s1", 9, 0), @@ -66,7 +66,7 @@ public class RegisterFile { new Register("t5", 30, 0), new Register("t6", 31, 0) }); - private static Register programCounter = new Register("pc", -1, Memory.textBaseAddress); + private static Register programCounter = new Register("pc", -1, Memory.configuration.getTextBaseAddress()); /** * This method updates the register value who's number is num. Also handles the lo and hi registers diff --git a/src/rars/simulator/ProgramArgumentList.java b/src/rars/simulator/ProgramArgumentList.java index a3b7fa55..cb6525f6 100644 --- a/src/rars/simulator/ProgramArgumentList.java +++ b/src/rars/simulator/ProgramArgumentList.java @@ -129,6 +129,8 @@ public ProgramArgumentList(ArrayList list, int startPosition) { // address holding the first argument pointer (argv). public void storeProgramArguments() { if (programArgumentList == null || programArgumentList.size() == 0) { + // If there is no input just make argc = 0 and argv = {NULL} by allocating two words on the stack + RegisterFile.getRegister("sp").setValue(Memory.configuration.getStackBaseAddress()-8); return; } // Runtime stack initialization from stack top-down (each is 4 bytes) : @@ -153,7 +155,7 @@ public void storeProgramArguments() { // Follow this pattern for all remaining arguments. - int highAddress = Memory.stackBaseAddress; // highest non-kernel address, sits "under" stack + int highAddress = Memory.configuration.getStackBaseAddress()-1; // first writeable byte in the stack String programArgument; int[] argStartAddress = new int[programArgumentList.size()]; try { // needed for all memory writes @@ -167,16 +169,11 @@ public void storeProgramArguments() { } argStartAddress[i] = highAddress + 1; } + + // Get on a word boundary to start writing argv + int stackAddress = highAddress - (highAddress % Memory.WORD_LENGTH_BYTES) - Memory.WORD_LENGTH_BYTES; + // now place a null word, the arg starting addresses, and arg count onto stack. - int stackAddress = Memory.stackPointer; // base address for runtime stack. - if (highAddress < Memory.stackPointer) { - // Based on current values for stackBaseAddress and stackPointer, this will - // only happen if the combined lengths of program arguments is greater than - // 0x7ffffffc - 0x7fffeffc = 0x00001000 = 4096 bytes. In this case, set - // stackAddress to next lower word boundary minus 4 for clearance (since every - // byte from highAddress+1 is filled). - stackAddress = highAddress - (highAddress % Memory.WORD_LENGTH_BYTES) - Memory.WORD_LENGTH_BYTES; - } Globals.memory.set(stackAddress, 0, Memory.WORD_LENGTH_BYTES); // null word for end of argv array stackAddress -= Memory.WORD_LENGTH_BYTES; for (int i = argStartAddress.length - 1; i >= 0; i--) { @@ -184,13 +181,12 @@ public void storeProgramArguments() { stackAddress -= Memory.WORD_LENGTH_BYTES; } Globals.memory.set(stackAddress, argStartAddress.length, Memory.WORD_LENGTH_BYTES); // argc - stackAddress -= Memory.WORD_LENGTH_BYTES; // Need to set $sp register to stack address, $a0 to argc, $a1 to argv // Need to by-pass the backstepping mechanism so go directly to Register instead of RegisterFile - RegisterFile.getRegister("sp").setValue(stackAddress + Memory.WORD_LENGTH_BYTES); + RegisterFile.getRegister("sp").setValue(stackAddress); RegisterFile.getRegister("a0").setValue(argStartAddress.length); // argc - RegisterFile.getRegister("a1").setValue(stackAddress + Memory.WORD_LENGTH_BYTES + Memory.WORD_LENGTH_BYTES); // argv + RegisterFile.getRegister("a1").setValue(stackAddress + Memory.WORD_LENGTH_BYTES); // argv } catch (AddressErrorException aee) { System.out.println("Internal Error: Memory write error occurred while storing program arguments! " + aee); System.exit(0); diff --git a/src/rars/tools/AbstractToolAndApplication.java b/src/rars/tools/AbstractToolAndApplication.java index 2ef1518c..c3a94500 100644 --- a/src/rars/tools/AbstractToolAndApplication.java +++ b/src/rars/tools/AbstractToolAndApplication.java @@ -79,8 +79,8 @@ public abstract class AbstractToolAndApplication extends JFrame implements Tool, private Color backgroundColor = Color.WHITE; - private int lowMemoryAddress = Memory.dataSegmentBaseAddress; - private int highMemoryAddress = Memory.stackBaseAddress; + private int lowMemoryAddress = Memory.configuration.total.low; + private int highMemoryAddress = Memory.configuration.total.high; // For Tool, is set true when "Connect" clicked, false when "Disconnect" clicked. // For app, is set true when "Assemble and Run" clicked, false when program terminates. private volatile boolean observing = false; diff --git a/src/rars/tools/BHTSimulator.java b/src/rars/tools/BHTSimulator.java index d363daf8..e04d4ddf 100644 --- a/src/rars/tools/BHTSimulator.java +++ b/src/rars/tools/BHTSimulator.java @@ -116,7 +116,7 @@ public BHTSimulator() { * Adds BHTSimulator as observer of the text segment. */ protected void addAsObserver() { - addAsObserver(Memory.textBaseAddress, Memory.textLimitAddress); + addAsObserver(Memory.configuration.text.low,Memory.configuration.text.high); addAsObserver(RegisterFile.getProgramCounterRegister()); } diff --git a/src/rars/tools/BitmapDisplay.java b/src/rars/tools/BitmapDisplay.java index 58808c71..ca6e5ffb 100644 --- a/src/rars/tools/BitmapDisplay.java +++ b/src/rars/tools/BitmapDisplay.java @@ -399,8 +399,13 @@ private JComponent buildVisualizationArea() { //dataSegmentBaseAddress=0x10000000, globalPointer=0x10008000 //dataBaseAddress=0x10010000, heapBaseAddress=0x10040000, memoryMapBaseAddress=0xffff0000 private void initializeDisplayBaseChoices() { - int[] displayBaseAddressArray = {Memory.dataSegmentBaseAddress, Memory.globalPointer, Memory.dataBaseAddress, - Memory.heapBaseAddress, Memory.memoryMapBaseAddress}; + int[] displayBaseAddressArray = { + Memory.configuration.getExternBaseAddress(), + Memory.configuration.getGlobalPointer(), + Memory.configuration.getDataBaseAddress(), + Memory.configuration.getHeapBaseAddress(), + Memory.configuration.getMemoryMapBaseAddress(), + }; // Must agree with above in number and order... String[] descriptions = {" (global data)", " (gp)", " (static data)", " (heap)", " (memory map)"}; displayBaseAddresses = displayBaseAddressArray; diff --git a/src/rars/tools/DigitalLabSim.java b/src/rars/tools/DigitalLabSim.java index 8ef7f915..dbd9a09b 100644 --- a/src/rars/tools/DigitalLabSim.java +++ b/src/rars/tools/DigitalLabSim.java @@ -43,11 +43,11 @@ public class DigitalLabSim extends AbstractToolAndApplication { public DigitalLabSim(String title, String heading) { super(title, heading); - IN_ADRESS_DISPLAY_1 = Memory.memoryMapBaseAddress + 0x10; - IN_ADRESS_DISPLAY_2 = Memory.memoryMapBaseAddress + 0x11; - IN_ADRESS_HEXA_KEYBOARD = Memory.memoryMapBaseAddress + 0x12; - IN_ADRESS_COUNTER = Memory.memoryMapBaseAddress + 0x13; - OUT_ADRESS_HEXA_KEYBOARD = Memory.memoryMapBaseAddress + 0x14; + IN_ADRESS_DISPLAY_1 = Memory.configuration.getMemoryMapBaseAddress() + 0x10; + IN_ADRESS_DISPLAY_2 = Memory.configuration.getMemoryMapBaseAddress() + 0x11; + IN_ADRESS_HEXA_KEYBOARD = Memory.configuration.getMemoryMapBaseAddress() + 0x12; + IN_ADRESS_COUNTER = Memory.configuration.getMemoryMapBaseAddress() + 0x13; + OUT_ADRESS_HEXA_KEYBOARD = Memory.configuration.getMemoryMapBaseAddress() + 0x14; } public DigitalLabSim() { @@ -65,7 +65,7 @@ public String getName() { protected void addAsObserver() { addAsObserver(IN_ADRESS_DISPLAY_1, IN_ADRESS_DISPLAY_1); - addAsObserver(Memory.textBaseAddress, Memory.textLimitAddress); + addAsObserver(Memory.configuration.text.low,Memory.configuration.text.high); } public void update(Observable ressource, Object accessNotice) { diff --git a/src/rars/tools/InstructionCounter.java b/src/rars/tools/InstructionCounter.java index bcf84694..7abdd34e 100644 --- a/src/rars/tools/InstructionCounter.java +++ b/src/rars/tools/InstructionCounter.java @@ -272,7 +272,7 @@ protected JComponent buildMainDisplayArea() { @Override protected void addAsObserver() { - addAsObserver(Memory.textBaseAddress, Memory.textLimitAddress); + addAsObserver(Memory.configuration.text.low,Memory.configuration.text.high); } @Override diff --git a/src/rars/tools/InstructionMemoryDump.java b/src/rars/tools/InstructionMemoryDump.java index 33b42e37..ec43746e 100644 --- a/src/rars/tools/InstructionMemoryDump.java +++ b/src/rars/tools/InstructionMemoryDump.java @@ -160,15 +160,10 @@ public String getName() { return name; } - private int lowDataSegmentAddress = Memory.dataSegmentBaseAddress; - private int highDataSegmentAddress = Memory.stackBaseAddress; - @Override protected void addAsObserver() { - // watch the text segment (the program) - addAsObserver(Memory.textBaseAddress, Memory.textLimitAddress); - // also watch the data segment - addAsObserver(lowDataSegmentAddress, highDataSegmentAddress); + // watch everything + addAsObserver(Memory.configuration.total.low,Memory.configuration.total.high); } @Override @@ -179,7 +174,7 @@ protected void processRISCVUpdate(Observable resource, AccessNotice notice) { int a = m.getAddress(); // is a in the text segment (program)? - if ((a >= Memory.textBaseAddress) && (a < Memory.textLimitAddress)) { + if (Memory.configuration.text.contains(a,m.getLength())) { if (notice.getAccessType() != AccessNotice.READ) return; if (a == lastAddress) return; lastAddress = a; @@ -204,10 +199,7 @@ protected void processRISCVUpdate(Observable resource, AccessNotice notice) { // TODO Auto-generated catch block e.printStackTrace(); } - } - - // is a in the data segment? - if ((a >= lowDataSegmentAddress) && (a < highDataSegmentAddress)) { + } else { if (notice.getAccessType() == AccessNotice.READ) log.append("L: 0x"); if (notice.getAccessType() == AccessNotice.WRITE) log.append("S: 0x"); log.append(Integer.toUnsignedString(a, 16) + "\n"); diff --git a/src/rars/tools/InstructionStatistics.java b/src/rars/tools/InstructionStatistics.java index f7508acb..09f85590 100644 --- a/src/rars/tools/InstructionStatistics.java +++ b/src/rars/tools/InstructionStatistics.java @@ -217,7 +217,7 @@ protected JComponent buildMainDisplayArea() { * registers the tool as observer for the text segment of the program */ protected void addAsObserver() { - addAsObserver(Memory.textBaseAddress, Memory.textLimitAddress); + addAsObserver(Memory.configuration.text.low,Memory.configuration.text.high); } // TODO: Port this to work with RISCV rather than MIPS diff --git a/src/rars/tools/KeyboardAndDisplaySimulator.java b/src/rars/tools/KeyboardAndDisplaySimulator.java index 4b8d9c25..64042e5b 100644 --- a/src/rars/tools/KeyboardAndDisplaySimulator.java +++ b/src/rars/tools/KeyboardAndDisplaySimulator.java @@ -168,10 +168,10 @@ public String getName() { // address space was final as well. Now we will get MMIO base address // each time to reflect possible change in memory configuration. DPS 6-Aug-09 protected void initializePreGUI() { - RECEIVER_CONTROL = Memory.memoryMapBaseAddress; //0xffff0000; // keyboard Ready in low-order bit - RECEIVER_DATA = Memory.memoryMapBaseAddress + 4; //0xffff0004; // keyboard character in low-order byte - TRANSMITTER_CONTROL = Memory.memoryMapBaseAddress + 8; //0xffff0008; // display Ready in low-order bit - TRANSMITTER_DATA = Memory.memoryMapBaseAddress + 12; //0xffff000c; // display character in low-order byte + RECEIVER_CONTROL = Memory.configuration.getMemoryMapBaseAddress(); //0xffff0000; // keyboard Ready in low-order bit + RECEIVER_DATA = Memory.configuration.getMemoryMapBaseAddress() + 4; //0xffff0004; // keyboard character in low-order byte + TRANSMITTER_CONTROL = Memory.configuration.getMemoryMapBaseAddress() + 8; //0xffff0008; // display Ready in low-order bit + TRANSMITTER_DATA = Memory.configuration.getMemoryMapBaseAddress() + 12; //0xffff000c; // display character in low-order byte displayPanelTitle = "DISPLAY: Store to Transmitter Data " + Binary.intToHexString(TRANSMITTER_DATA); keyboardPanelTitle = "KEYBOARD: Characters typed here are stored to Receiver Data " + Binary.intToHexString(RECEIVER_DATA); } @@ -200,7 +200,7 @@ protected void addAsObserver() { // basis for delay in re-setting (literally) the TRANSMITTER_CONTROL register. SPIM does // this too. This simulates the time required for the display unit to process the // TRANSMITTER_DATA. - addAsObserver(Memory.textBaseAddress, Memory.textLimitAddress); + addAsObserver(Memory.configuration.text.low,Memory.configuration.text.high); } /** diff --git a/src/rars/tools/MemoryReferenceVisualization.java b/src/rars/tools/MemoryReferenceVisualization.java index d0b55f11..10c6a676 100644 --- a/src/rars/tools/MemoryReferenceVisualization.java +++ b/src/rars/tools/MemoryReferenceVisualization.java @@ -457,8 +457,16 @@ private JComponent buildVisualizationArea() { //textBaseAddress=0x00400000, dataSegmentBaseAddress=0x10000000, globalPointer=0x10008000 //dataBaseAddress=0x10010000, heapBaseAddress=0x10040000, memoryMapBaseAddress=0xffff0000 private void initializeDisplayBaseChoices() { - int[] displayBaseAddressArray = {Memory.textBaseAddress, Memory.dataSegmentBaseAddress, Memory.globalPointer, Memory.dataBaseAddress, - Memory.heapBaseAddress, Memory.memoryMapBaseAddress}; + int[] displayBaseAddressArray = { + Memory.configuration.getTextBaseAddress(), + Memory.configuration.getExternBaseAddress(), + Memory.configuration.getGlobalPointer(), + Memory.configuration.getDataBaseAddress(), + Memory.configuration.getHeapBaseAddress(), + Memory.configuration.getMemoryMapBaseAddress(), + }; + + // Must agree with above in number and order... String[] descriptions = {" (text)", " (global data)", " (gp)", " (static data)", " (heap)", " (memory map)"}; displayBaseAddresses = displayBaseAddressArray; diff --git a/src/rars/tools/TimerTool.java b/src/rars/tools/TimerTool.java index 99213e2a..b6f8e540 100644 --- a/src/rars/tools/TimerTool.java +++ b/src/rars/tools/TimerTool.java @@ -50,8 +50,8 @@ a copy of this software and associated documentation files (the public class TimerTool extends AbstractToolAndApplication { private static String heading = "Timer Tool"; private static String version = "Version 1.0 (Zachary Selk)"; - private static final int TIME_ADDRESS = Memory.memoryMapBaseAddress + 0x18; - private static final int TIME_CMP_ADDRESS = Memory.memoryMapBaseAddress + 0x20; + private static final int TIME_ADDRESS = Memory.configuration.getMemoryMapBaseAddress() + 0x18; + private static final int TIME_CMP_ADDRESS = Memory.configuration.getMemoryMapBaseAddress() + 0x20; // GUI window sections private static JPanel panelTools; diff --git a/src/rars/util/MemoryDump.java b/src/rars/util/MemoryDump.java deleted file mode 100644 index ed5847b0..00000000 --- a/src/rars/util/MemoryDump.java +++ /dev/null @@ -1,93 +0,0 @@ -package rars.util; - -import rars.riscv.hardware.Memory; - - /* -Copyright (c) 2003-2009, Pete Sanderson and Kenneth Vollmar - -Developed by Pete Sanderson (psanderson@otterbein.edu) -and Kenneth Vollmar (kenvollmar@missouristate.edu) - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject -to the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR -ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF -CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -(MIT license, http://www.opensource.org/licenses/mit-license.html) - */ -// TODO: refactor this out of existance -public class MemoryDump { - private static final String[] segmentNames = {".text", ".data"}; - private static int[] baseAddresses = new int[2]; - private static int[] limitAddresses = new int[2]; - - /** - * Return array with segment address bounds for specified segment. - * - * @param segment String with segment name (initially ".text" and ".data") - * @return array of two Integer, the base and limit address for that segment. Null if parameter - * name does not match a known segment name. - */ - public static Integer[] getSegmentBounds(String segment) { - for (int i = 0; i < segmentNames.length; i++) { - if (segmentNames[i].equals(segment)) { - Integer[] bounds = new Integer[2]; - bounds[0] = getBaseAddresses(segmentNames)[i]; - bounds[1] = getLimitAddresses(segmentNames)[i]; - return bounds; - } - } - return null; - } - - /** - * Get the names of segments available for memory dump. - * - * @return array of Strings, each string is segment name (e.g. ".text", ".data") - */ - public static String[] getSegmentNames() { - return segmentNames; - } - - /** - * Get the base address(es) of the specified segment name(s). - * If invalid segment name is provided, will throw NullPointerException, so - * I recommend getting segment names from getSegmentNames(). - * - * @param segments Array of Strings containing segment names (".text", ".data") - * @return Array of int containing corresponding base addresses. - */ - public static int[] getBaseAddresses(String[] segments) { - baseAddresses[0] = Memory.textBaseAddress; - baseAddresses[1] = Memory.dataBaseAddress; - return baseAddresses; - } - - /** - * Get the limit address(es) of the specified segment name(s). - * If invalid segment name is provided, will throw NullPointerException, so - * I recommend getting segment names from getSegmentNames(). - * - * @param segments Array of Strings containing segment names (".text", ".data") - * @return Array of int containing corresponding limit addresses. - */ - public static int[] getLimitAddresses(String[] segments) { - limitAddresses[0] = Memory.textLimitAddress; - limitAddresses[1] = Memory.dataSegmentLimitAddress; - return limitAddresses; - } -} \ No newline at end of file diff --git a/src/rars/venus/DataSegmentWindow.java b/src/rars/venus/DataSegmentWindow.java index 963787ad..10345e32 100644 --- a/src/rars/venus/DataSegmentWindow.java +++ b/src/rars/venus/DataSegmentWindow.java @@ -88,7 +88,6 @@ public class DataSegmentWindow extends JInternalFrame implements Observer { private int firstAddress; private int homeAddress; - private boolean userOrKernelMode; // The combo box replaced the row of buttons when number of buttons expanded to 7! // We'll keep the button objects however and manually invoke their action listeners @@ -114,9 +113,8 @@ public DataSegmentWindow(NumberDisplayBaseChooser[] choosers) { settings = Globals.getSettings(); settings.addObserver(this); - homeAddress = Memory.dataBaseAddress; // address for Home button + homeAddress = Memory.configuration.getDataBaseAddress(); // address for Home button firstAddress = homeAddress; // first address to display at any given time - userOrKernelMode = USER_MODE; addressHighlighting = false; contentPane = this.getContentPane(); tablePanel = new JPanel(new GridLayout(1, 2, 10, 0)); @@ -178,13 +176,13 @@ public void itemStateChanged(ItemEvent e) { public void updateBaseAddressComboBox() { - displayBaseAddressArray[EXTERN_BASE_ADDRESS_INDEX] = Memory.externBaseAddress; - displayBaseAddressArray[GLOBAL_POINTER_ADDRESS_INDEX] = -1; /*Memory.globalPointer*/ - displayBaseAddressArray[DATA_BASE_ADDRESS_INDEX] = Memory.dataBaseAddress; - displayBaseAddressArray[HEAP_BASE_ADDRESS_INDEX] = Memory.heapBaseAddress; - displayBaseAddressArray[STACK_POINTER_BASE_ADDRESS_INDEX] = -1; /*Memory.stackPointer*/ - displayBaseAddressArray[MMIO_BASE_ADDRESS_INDEX] = Memory.memoryMapBaseAddress; - displayBaseAddressArray[TEXT_BASE_ADDRESS_INDEX] = Memory.textBaseAddress; + displayBaseAddressArray[EXTERN_BASE_ADDRESS_INDEX] = Memory.configuration.getExternBaseAddress(); + displayBaseAddressArray[GLOBAL_POINTER_ADDRESS_INDEX] = Memory.configuration.getGlobalPointer(); + displayBaseAddressArray[DATA_BASE_ADDRESS_INDEX] = Memory.configuration.getDataBaseAddress(); + displayBaseAddressArray[HEAP_BASE_ADDRESS_INDEX] = Memory.configuration.getHeapBaseAddress(); + displayBaseAddressArray[STACK_POINTER_BASE_ADDRESS_INDEX] = Memory.configuration.getStackBaseAddress(); + displayBaseAddressArray[MMIO_BASE_ADDRESS_INDEX] = Memory.configuration.getMemoryMapBaseAddress(); + displayBaseAddressArray[TEXT_BASE_ADDRESS_INDEX] = Memory.configuration.getTextBaseAddress(); displayBaseAddressChoices = createBaseAddressLabelsArray(displayBaseAddressArray, descriptions); baseAddressSelector.setModel(new CustomComboBoxModel(displayBaseAddressChoices)); displayBaseAddresses = displayBaseAddressArray; @@ -322,10 +320,15 @@ private Point displayCellForAddress(int address) { private static final int STACK_POINTER_BASE_ADDRESS_INDEX = 4; //5; private static final int MMIO_BASE_ADDRESS_INDEX = 6; // Must agree with above in number and order... - private int[] displayBaseAddressArray = {Memory.externBaseAddress, - Memory.dataBaseAddress, Memory.heapBaseAddress, -1 /*Memory.globalPointer*/, - -1 /*Memory.stackPointer*/, Memory.textBaseAddress, - Memory.memoryMapBaseAddress,}; + private int[] displayBaseAddressArray = { + Memory.configuration.getExternBaseAddress(), + Memory.configuration.getDataBaseAddress(), + Memory.configuration.getHeapBaseAddress(), + -1, // GP + -1, // SP + Memory.configuration.getTextBaseAddress(), + Memory.configuration.getMemoryMapBaseAddress(), + }; // Must agree with above in number and order... String[] descriptions = {" (.extern)", " (.data)", " (heap)", "current gp", "current sp", " (.text)", " (MMIO)"}; @@ -374,7 +377,7 @@ private int getBaseAddressIndexForAddress(int address) { int shortDistance = 0x7fffffff; int thisDistance; // Check distance from .extern base. Cannot be below it - thisDistance = address - Memory.externBaseAddress; + thisDistance = address - Memory.configuration.getExternBaseAddress(); if (thisDistance >= 0 && thisDistance < shortDistance) { shortDistance = thisDistance; desiredComboBoxIndex = EXTERN_BASE_ADDRESS_INDEX; @@ -386,13 +389,13 @@ private int getBaseAddressIndexForAddress(int address) { desiredComboBoxIndex = GLOBAL_POINTER_ADDRESS_INDEX; } // Check distance from .data base. Cannot be below it - thisDistance = address - Memory.dataBaseAddress; + thisDistance = address -Memory.configuration.getDataBaseAddress(); if (thisDistance >= 0 && thisDistance < shortDistance) { shortDistance = thisDistance; desiredComboBoxIndex = DATA_BASE_ADDRESS_INDEX; } // Check distance from heap base. Cannot be below it - thisDistance = address - Memory.heapBaseAddress; + thisDistance = address -Memory.configuration.getHeapBaseAddress(); if (thisDistance >= 0 && thisDistance < shortDistance) { shortDistance = thisDistance; desiredComboBoxIndex = HEAP_BASE_ADDRESS_INDEX; @@ -658,17 +661,17 @@ private void addButtonActionListenersAndInitialize() { globButton.setToolTipText("View range around global pointer"); stakButton.setToolTipText("View range around stack pointer"); heapButton.setToolTipText("View range around heap base address " + - Binary.intToHexString(Memory.heapBaseAddress)); + Binary.intToHexString(Memory.configuration.getHeapBaseAddress())); extnButton.setToolTipText("View range around static global base address " + - Binary.intToHexString(Memory.externBaseAddress)); + Binary.intToHexString(Memory.configuration.getGlobalPointer())); mmioButton.setToolTipText("View range around MMIO base address " + - Binary.intToHexString(Memory.memoryMapBaseAddress)); + Binary.intToHexString(Memory.configuration.getMemoryMapBaseAddress())); textButton.setToolTipText("View range around program code " + - Binary.intToHexString(Memory.textBaseAddress)); + Binary.intToHexString(Memory.configuration.getTextBaseAddress())); prevButton.setToolTipText("View next lower address range; hold down for rapid fire"); nextButton.setToolTipText("View next higher address range; hold down for rapid fire"); dataButton.setToolTipText("View range around static data segment base address " + - Binary.intToHexString(Memory.dataBaseAddress)); + Binary.intToHexString(Memory.configuration.getDataBaseAddress())); // add the action listeners to maintain button state and table contents // Currently there is no memory upper bound so next button always enabled. @@ -676,9 +679,9 @@ private void addButtonActionListenersAndInitialize() { globButton.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent ae) { - userOrKernelMode = USER_MODE; // get $gp global pointer, but guard against it having value below data segment - firstAddress = Math.max(Memory.dataSegmentBaseAddress, RegisterFile.getValue(RegisterFile.GLOBAL_POINTER_REGISTER)); + firstAddress = Math.max( +Memory.configuration.getDataSegmentBaseAddress(), RegisterFile.getValue(RegisterFile.GLOBAL_POINTER_REGISTER)); // updateModelForMemoryRange requires argument to be multiple of 4 // but for cleaner display we'll make it multiple of 32 (last nibble is 0). // This makes it easier to mentally calculate address from row address + column offset. @@ -692,12 +695,11 @@ public void actionPerformed(ActionEvent ae) { stakButton.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent ae) { - userOrKernelMode = USER_MODE; // get $sp stack pointer, but guard against it having value below data segment - firstAddress = Math.max(Memory.dataSegmentBaseAddress, RegisterFile.getValue(RegisterFile.STACK_POINTER_REGISTER)); + firstAddress = Math.max(Memory.configuration.getDataSegmentBaseAddress(), RegisterFile.getValue(RegisterFile.STACK_POINTER_REGISTER)); // See comment above for gloButton... firstAddress = firstAddress - (firstAddress % BYTES_PER_ROW); - homeAddress = Memory.stackBaseAddress; + homeAddress = Memory.configuration.getStackBaseAddress(); firstAddress = setFirstAddressAndPrevNextButtonEnableStatus(firstAddress); updateModelForMemoryRange(firstAddress); } @@ -706,8 +708,7 @@ public void actionPerformed(ActionEvent ae) { heapButton.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent ae) { - userOrKernelMode = USER_MODE; - homeAddress = Memory.heapBaseAddress; + homeAddress = Memory.configuration.getHeapBaseAddress(); firstAddress = setFirstAddressAndPrevNextButtonEnableStatus(homeAddress); updateModelForMemoryRange(firstAddress); } @@ -716,8 +717,7 @@ public void actionPerformed(ActionEvent ae) { extnButton.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent ae) { - userOrKernelMode = USER_MODE; - homeAddress = Memory.externBaseAddress; + homeAddress = Memory.configuration.getExternBaseAddress(); firstAddress = setFirstAddressAndPrevNextButtonEnableStatus(homeAddress); updateModelForMemoryRange(firstAddress); } @@ -726,8 +726,7 @@ public void actionPerformed(ActionEvent ae) { mmioButton.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent ae) { - userOrKernelMode = KERNEL_MODE; - homeAddress = Memory.memoryMapBaseAddress; + homeAddress = Memory.configuration.getMemoryMapBaseAddress(); firstAddress = homeAddress; firstAddress = setFirstAddressAndPrevNextButtonEnableStatus(firstAddress); updateModelForMemoryRange(firstAddress); @@ -737,8 +736,7 @@ public void actionPerformed(ActionEvent ae) { textButton.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent ae) { - userOrKernelMode = USER_MODE; - homeAddress = Memory.textBaseAddress; + homeAddress = Memory.configuration.getTextBaseAddress(); firstAddress = homeAddress; firstAddress = setFirstAddressAndPrevNextButtonEnableStatus(firstAddress); updateModelForMemoryRange(firstAddress); @@ -748,8 +746,7 @@ public void actionPerformed(ActionEvent ae) { dataButton.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent ae) { - userOrKernelMode = USER_MODE; - homeAddress = Memory.dataBaseAddress; + homeAddress = Memory.configuration.getDataBaseAddress(); firstAddress = homeAddress; firstAddress = setFirstAddressAndPrevNextButtonEnableStatus(firstAddress); updateModelForMemoryRange(firstAddress); @@ -774,19 +771,16 @@ public void actionPerformed(ActionEvent ae) { // PrevButton and NextButton are enabled/disabled appropriately. // private int setFirstAddressAndPrevNextButtonEnableStatus(int lowAddress) { - int lowLimit = (userOrKernelMode == USER_MODE) ? Math.min(Math.min(Memory.textBaseAddress, - Memory.dataSegmentBaseAddress), - Memory.dataBaseAddress) - : Memory.memoryMapBaseAddress; - int highLimit = (userOrKernelMode == USER_MODE) ? Memory.userHighAddress - : Memory.kernelHighAddress; - if (lowAddress <= lowLimit) { + int lowLimit = Memory.configuration.total.low; + int highLimit = Memory.configuration.total.high; + + if (Integer.compareUnsigned(lowAddress,lowLimit) <= 0) { lowAddress = lowLimit; prevButton.setEnabled(false); } else { prevButton.setEnabled(true); } - if (lowAddress >= highLimit - MEMORY_CHUNK_SIZE) { + if (Integer.compareUnsigned(lowAddress,highLimit - MEMORY_CHUNK_SIZE) >= 0) { lowAddress = highLimit - MEMORY_CHUNK_SIZE + 1; nextButton.setEnabled(false); } else { diff --git a/src/rars/venus/FileDumpMemoryAction.java b/src/rars/venus/FileDumpMemoryAction.java index 375fd57e..8fa2797e 100644 --- a/src/rars/venus/FileDumpMemoryAction.java +++ b/src/rars/venus/FileDumpMemoryAction.java @@ -5,8 +5,8 @@ import rars.riscv.dump.DumpFormatLoader; import rars.riscv.hardware.AddressErrorException; import rars.riscv.hardware.Memory; +import rars.riscv.hardware.Range; import rars.util.Binary; -import rars.util.MemoryDump; import javax.swing.*; import javax.swing.border.EmptyBorder; @@ -56,13 +56,6 @@ public class FileDumpMemoryAction extends GuiAction { private JDialog dumpDialog; private static final String title = "Dump Memory To File"; - // A series of parallel arrays representing the memory segments that can be dumped. - private String[] segmentArray; - private int[] baseAddressArray; - private int[] limitAddressArray; - private int[] highAddressArray; - // These three are allocated and filled by buildDialogPanel() and used by action listeners. - private String[] segmentListArray; private int[] segmentListBaseArray; private int[] segmentListHighArray; @@ -112,13 +105,14 @@ private JPanel buildDialogPanel() { JPanel contents = new JPanel(new BorderLayout(20, 20)); contents.setBorder(new EmptyBorder(10, 10, 10, 10)); - segmentArray = MemoryDump.getSegmentNames(); - baseAddressArray = MemoryDump.getBaseAddresses(segmentArray); - limitAddressArray = MemoryDump.getLimitAddresses(segmentArray); - highAddressArray = new int[segmentArray.length]; + // A series of parallel arrays representing the memory segments that can be dumped. + String[] segmentArray = new String[]{".text", ".data"}; + Range[] segments = new Range[]{Memory.configuration.text,Memory.configuration.data}; + int[] highAddressArray = new int[segmentArray.length]; - segmentListArray = new String[segmentArray.length]; + // These three are allocated and filled by buildDialogPanel() and used by action listeners. + String[] segmentListArray = new String[segmentArray.length]; segmentListBaseArray = new int[segmentArray.length]; segmentListHighArray = new int[segmentArray.length]; @@ -134,18 +128,18 @@ private JPanel buildDialogPanel() { for (int i = 0; i < segmentArray.length; i++) { try { - highAddressArray[i] = Globals.memory.getAddressOfFirstNull(baseAddressArray[i], limitAddressArray[i]) - Memory.WORD_LENGTH_BYTES; + highAddressArray[i] = Globals.memory.getAddressOfFirstNull(segments[i].low, segments[i].high) - Memory.WORD_LENGTH_BYTES; } // Exception will not happen since the Memory base and limit addresses are on word boundaries! catch (AddressErrorException aee) { - highAddressArray[i] = baseAddressArray[i] - Memory.WORD_LENGTH_BYTES; + highAddressArray[i] = segments[i].low - Memory.WORD_LENGTH_BYTES; } - if (highAddressArray[i] >= baseAddressArray[i]) { - segmentListBaseArray[segmentCount] = baseAddressArray[i]; - segmentListHighArray[segmentCount] = highAddressArray[i]; + if (highAddressArray[i] >= segments[i].low) { + segmentListBaseArray[segmentCount] = segments[i].low; + segmentListHighArray[segmentCount] = segments[i].high; segmentListArray[segmentCount] = - segmentArray[i] + " (" + Binary.intToHexString(baseAddressArray[i]) + - " - " + Binary.intToHexString(highAddressArray[i]) + ")"; + segmentArray[i] + " (" + Binary.intToHexString(segments[i].low) + + " - " + Binary.intToHexString(segments[i].high) + ")"; segmentCount++; } } diff --git a/src/rars/venus/TextSegmentWindow.java b/src/rars/venus/TextSegmentWindow.java index 59ef000e..b5ef8f8d 100644 --- a/src/rars/venus/TextSegmentWindow.java +++ b/src/rars/venus/TextSegmentWindow.java @@ -606,7 +606,7 @@ public void toggleBreakpoints() { */ private void addAsTextSegmentObserver() { try { - Memory.getInstance().addObserver(this, Memory.textBaseAddress, Memory.dataSegmentBaseAddress); + Memory.getInstance().addObserver(this, Memory.configuration.getTextBaseAddress(),Memory.configuration.getDataSegmentBaseAddress()); } catch (AddressErrorException aee) { } } diff --git a/src/rars/venus/run/RunAssembleAction.java b/src/rars/venus/run/RunAssembleAction.java index 5e5bec6c..ab08146c 100644 --- a/src/rars/venus/run/RunAssembleAction.java +++ b/src/rars/venus/run/RunAssembleAction.java @@ -127,7 +127,7 @@ public void actionPerformed(ActionEvent e) { executePane.getTextSegmentWindow().setupTable(); executePane.getDataSegmentWindow().setupTable(); - executePane.getDataSegmentWindow().highlightCellForAddress(Memory.dataBaseAddress); + executePane.getDataSegmentWindow().highlightCellForAddress(Memory.configuration.getDataBaseAddress()); executePane.getDataSegmentWindow().clearHighlighting(); executePane.getLabelsWindow().setupTable(); executePane.getTextSegmentWindow().setCodeHighlighting(true); diff --git a/src/rars/venus/run/RunGoAction.java b/src/rars/venus/run/RunGoAction.java index d4c152dc..aae27d58 100644 --- a/src/rars/venus/run/RunGoAction.java +++ b/src/rars/venus/run/RunGoAction.java @@ -221,8 +221,7 @@ public static void resetMaxSteps() { // $a0 gets argument count (argc), $a1 gets stack address of first arg pointer (argv). private void processProgramArgumentsIfAny() { String programArguments = executePane.getTextSegmentWindow().getProgramArguments(); - if (programArguments == null || programArguments.length() == 0 || - !Globals.getSettings().getBooleanSetting(Settings.Bool.PROGRAM_ARGUMENTS)) { + if (programArguments == null || !Globals.getSettings().getBooleanSetting(Settings.Bool.PROGRAM_ARGUMENTS)) { return; } new ProgramArgumentList(programArguments).storeProgramArguments(); diff --git a/src/rars/venus/run/RunResetAction.java b/src/rars/venus/run/RunResetAction.java index 4659bf69..e3aa7138 100644 --- a/src/rars/venus/run/RunResetAction.java +++ b/src/rars/venus/run/RunResetAction.java @@ -90,7 +90,7 @@ public void actionPerformed(ActionEvent e) { executePane.getFloatingPointWindow().updateRegisters(); executePane.getControlAndStatusWindow().clearHighlighting(); executePane.getControlAndStatusWindow().updateRegisters(); - executePane.getDataSegmentWindow().highlightCellForAddress(Memory.dataBaseAddress); + executePane.getDataSegmentWindow().highlightCellForAddress(Memory.configuration.getDataBaseAddress()); executePane.getDataSegmentWindow().clearHighlighting(); executePane.getTextSegmentWindow().resetModifiedSourceCode(); executePane.getTextSegmentWindow().setCodeHighlighting(true); diff --git a/src/rars/venus/run/RunStepAction.java b/src/rars/venus/run/RunStepAction.java index 96b86bae..c9eeb35e 100644 --- a/src/rars/venus/run/RunStepAction.java +++ b/src/rars/venus/run/RunStepAction.java @@ -142,8 +142,7 @@ public void stepped(boolean done, Simulator.Reason reason, SimulationException p // $a0 gets argument count (argc), $a1 gets stack address of first arg pointer (argv). private void processProgramArgumentsIfAny() { String programArguments = executePane.getTextSegmentWindow().getProgramArguments(); - if (programArguments == null || programArguments.length() == 0 || - !Globals.getSettings().getBooleanSetting(Settings.Bool.PROGRAM_ARGUMENTS)) { + if (programArguments == null || !Globals.getSettings().getBooleanSetting(Settings.Bool.PROGRAM_ARGUMENTS)) { return; } new ProgramArgumentList(programArguments).storeProgramArguments(); diff --git a/src/rars/venus/settings/SettingsMemoryConfigurationAction.java b/src/rars/venus/settings/SettingsMemoryConfigurationAction.java index c2ebf72d..4b1e5d76 100644 --- a/src/rars/venus/settings/SettingsMemoryConfigurationAction.java +++ b/src/rars/venus/settings/SettingsMemoryConfigurationAction.java @@ -3,6 +3,7 @@ import rars.Globals; import rars.riscv.hardware.MemoryConfiguration; import rars.riscv.hardware.MemoryConfigurations; +import rars.riscv.hardware.Range; import rars.simulator.Simulator; import rars.util.Binary; import rars.venus.FileStatus; @@ -15,6 +16,8 @@ import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; +import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.util.Iterator; import java.util.Map; import java.util.TreeMap; @@ -129,8 +132,8 @@ private Component buildConfigChooser() { private Component buildConfigDisplay() { JPanel displayPanel = new JPanel(); MemoryConfiguration config = MemoryConfigurations.getCurrentConfiguration(); - String[] configurationItemNames = config.getConfigurationItemNames(); - int numItems = configurationItemNames.length; + Map ranges = config.sections; + int numItems = ranges.size()+2; JPanel namesPanel = new JPanel(new GridLayout(numItems, 1)); JPanel valuesPanel = new JPanel(new GridLayout(numItems, 1)); Font monospaced = new Font("Monospaced", Font.PLAIN, 12); @@ -205,6 +208,24 @@ public void actionPerformed(ActionEvent e) { performReset(); } }); + JButton loadButton = new JButton("Load"); + loadButton.setToolTipText("Load a properties files that specifies a config. Check the wiki"); + loadButton.addActionListener(e -> { + JFileChooser choose = new JFileChooser(); + if(JFileChooser.APPROVE_OPTION == choose.showOpenDialog(this)){ + System.out.println("You chose to open this file: " + choose.getSelectedFile().getName()); + try { + MemoryConfiguration mc = MemoryConfigurations.loadNewConfig(new FileInputStream(choose.getSelectedFile())); + if(MemoryConfigurations.getConfigurationByName(mc.getConfigurationName()) == null){ + MemoryConfigurations.addNewConfig(mc); + this.setContentPane(buildDialogPanel()); + this.setVisible(true); + } + } catch (FileNotFoundException ex) { + return; + } + } + }); controlPanel.add(Box.createHorizontalGlue()); controlPanel.add(okButton); controlPanel.add(Box.createHorizontalGlue()); @@ -214,6 +235,8 @@ public void actionPerformed(ActionEvent e) { controlPanel.add(Box.createHorizontalGlue()); controlPanel.add(resetButton); controlPanel.add(Box.createHorizontalGlue()); + controlPanel.add(loadButton); + controlPanel.add(Box.createHorizontalGlue()); return controlPanel; } @@ -251,25 +274,26 @@ private void performReset() { // Set name values in JLabels and address values in the JTextFields private void setConfigDisplay(MemoryConfiguration config) { - String[] configurationItemNames = config.getConfigurationItemNames(); - int[] configurationItemValues = config.getConfigurationItemValues(); + Map ranges = config.sections; + TreeMap treeSortedByAddress = new TreeMap<>(); + String rangestring=""; + for (Map.Entry entry: ranges.entrySet()) { + rangestring = Binary.intToHexString(entry.getValue().low) + "-" + Binary.intToHexString(entry.getValue().high); + treeSortedByAddress.put(rangestring,entry.getKey()); + } + treeSortedByAddress.put(Binary.intToHexString(config.extern_size + config.data.low),"Default .data start"); + treeSortedByAddress.put(Binary.intToHexString(config.gp_offset + config.data.low),"Global pointer"); + // Will use TreeMap to extract list of address-name pairs sorted by // hex-stringified address. This will correctly handle kernel addresses, // whose int values are negative and thus normal sorting yields incorrect - // results. There can be duplicate addresses, so I concatenate the name - // onto the address to make each key unique. Then slice off the name upon - // extraction. - TreeMap treeSortedByAddress = new TreeMap<>(); - for (int i = 0; i < configurationItemValues.length; i++) { - treeSortedByAddress.put(Binary.intToHexString(configurationItemValues[i]) + configurationItemNames[i], configurationItemNames[i]); - } + // results. Iterator> setSortedByAddress = treeSortedByAddress.entrySet().iterator(); Map.Entry pair; - int addressStringLength = Binary.intToHexString(configurationItemValues[0]).length(); - for (int i = 0; i < configurationItemValues.length; i++) { + for (int i = 0; i < treeSortedByAddress.size(); i++) { pair = setSortedByAddress.next(); nameDisplay[i].setText(pair.getValue()); - addressDisplay[i].setText(pair.getKey().substring(0, addressStringLength)); + addressDisplay[i].setText(pair.getKey()); } }