From e22efc100b09eb98e10d37a6e19ff5cf58a4bf39 Mon Sep 17 00:00:00 2001 From: Benjamin Landers Date: Mon, 2 Dec 2019 03:35:23 -0800 Subject: [PATCH 01/12] Refactored all accesses to memory for .data into a single spot An alternative assembler could be made that returns a list of statements and list of datastructs. Maybe space should allocate a 0 length write at the start and endto make sure that that gets included in the total length of the data section. That would allow generating an elf file and therefore allow more compatability testing. --- src/rars/assembler/Assembler.java | 99 ++++++++++++++++--------------- 1 file changed, 50 insertions(+), 49 deletions(-) diff --git a/src/rars/assembler/Assembler.java b/src/rars/assembler/Assembler.java index fa88542b..f41a259b 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 * @@ -107,6 +120,7 @@ public ArrayList assemble(ArrayList tokenizedPro 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 } From 078f2582eea3530563dcb3a30139c7a67507a804 Mon Sep 17 00:00:00 2001 From: Benjamin Landers Date: Mon, 2 Dec 2019 15:03:09 -0800 Subject: [PATCH 02/12] Remove big endian option --- src/rars/riscv/hardware/Memory.java | 95 ++--------------------------- 1 file changed, 5 insertions(+), 90 deletions(-) diff --git a/src/rars/riscv/hardware/Memory.java b/src/rars/riscv/hardware/Memory.java index 9301aad6..2e079aa7 100644 --- a/src/rars/riscv/hardware/Memory.java +++ b/src/rars/riscv/hardware/Memory.java @@ -104,17 +104,6 @@ public class Memory extends Observable { // 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; // Memory will maintain a collection of observables. Each one is associated @@ -442,45 +431,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 +492,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 +511,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. @@ -682,39 +629,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)); } ///////////////////////////////////////////////////////////////////////// @@ -1210,7 +1125,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); From 65aa431708e7a491ccec0f57ed47edf90997f804 Mon Sep 17 00:00:00 2001 From: Benjamin Landers Date: Tue, 3 Dec 2019 15:26:48 -0800 Subject: [PATCH 03/12] WIP: Removed static configuration variables in Memory Also removed util.MemoryDump and changed memory configurations significantly This is now compiling and passing automated tests, but doesn't have correct GUI behaviour. --- src/rars/Launch.java | 18 +- src/rars/assembler/Assembler.java | 6 +- src/rars/riscv/hardware/Memory.java | 140 +++---------- .../riscv/hardware/MemoryConfiguration.java | 73 +++---- .../riscv/hardware/MemoryConfigurations.java | 194 +++--------------- src/rars/riscv/hardware/Range.java | 18 ++ src/rars/riscv/hardware/RegisterFile.java | 6 +- src/rars/simulator/ProgramArgumentList.java | 6 +- .../tools/AbstractToolAndApplication.java | 4 +- src/rars/tools/BHTSimulator.java | 2 +- src/rars/tools/BitmapDisplay.java | 9 +- src/rars/tools/DigitalLabSim.java | 12 +- src/rars/tools/InstructionCounter.java | 2 +- src/rars/tools/InstructionMemoryDump.java | 16 +- src/rars/tools/InstructionStatistics.java | 2 +- .../tools/KeyboardAndDisplaySimulator.java | 10 +- .../tools/MemoryReferenceVisualization.java | 12 +- src/rars/tools/TimerTool.java | 4 +- src/rars/util/MemoryDump.java | 93 --------- src/rars/venus/DataSegmentWindow.java | 70 ++++--- src/rars/venus/FileDumpMemoryAction.java | 34 ++- src/rars/venus/TextSegmentWindow.java | 2 +- src/rars/venus/run/RunAssembleAction.java | 2 +- src/rars/venus/run/RunResetAction.java | 2 +- 24 files changed, 222 insertions(+), 515 deletions(-) create mode 100644 src/rars/riscv/hardware/Range.java delete mode 100644 src/rars/util/MemoryDump.java diff --git a/src/rars/Launch.java b/src/rars/Launch.java index 08174554..e5dd9e9f 100644 --- a/src/rars/Launch.java +++ b/src/rars/Launch.java @@ -4,11 +4,9 @@ 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; @@ -19,8 +17,6 @@ import java.io.PrintStream; 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 +171,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 +193,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) { @@ -672,7 +666,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]; diff --git a/src/rars/assembler/Assembler.java b/src/rars/assembler/Assembler.java index f41a259b..4e0fe596 100644 --- a/src/rars/assembler/Assembler.java +++ b/src/rars/assembler/Assembler.java @@ -112,9 +112,9 @@ 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(); diff --git a/src/rars/riscv/hardware/Memory.java b/src/rars/riscv/hardware/Memory.java index 2e079aa7..0d4a02a3 100644 --- a/src/rars/riscv/hardware/Memory.java +++ b/src/rars/riscv/hardware/Memory.java @@ -48,63 +48,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; - 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 @@ -191,15 +141,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() @@ -208,6 +149,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. **/ @@ -286,34 +230,13 @@ 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); + configuration = MemoryConfigurations.getCurrentConfiguration(); + 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][]; @@ -321,6 +244,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 @@ -339,11 +264,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.bss.high) { throw new IllegalArgumentException("request (" + numBytes + ") exceeds available heap storage"); } heapAddress = newHeapAddress; return result; + } /* ******************************* THE SETTER METHODS ******************************/ @@ -369,12 +295,12 @@ public int set(int address, int value, int length) throws AddressErrorException int relativeByteAddress; if (inDataSegment(address)) { // 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)) { // 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)) { // Burch Mod (Jan 2013): replace throw with call to setStatement @@ -405,9 +331,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)) { // memory mapped I/O. - relativeByteAddress = address - memoryMapBaseAddress; + relativeByteAddress = address - configuration.mmio.low; oldValue = storeBytesInTable(memoryMapBlockTable, relativeByteAddress, length, value); } else { // falls outside addressing range @@ -544,7 +470,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); } @@ -572,15 +498,15 @@ private int get(int address, int length, boolean notify) throws AddressErrorExce int relativeByteAddress; if (inDataSegment(address)) { // 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)) { // 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)) { // memory mapped I/O. - relativeByteAddress = address - memoryMapBaseAddress; + relativeByteAddress = address - configuration.mmio.low; value = fetchBytesFromTable(memoryMapBlockTable, relativeByteAddress, length); } else if (inTextSegment(address)) { // Burch Mod (Jan 2013): replace throw with calls to getStatementNoNotify & getBinaryStatement @@ -660,11 +586,11 @@ public Integer getRawWordOrNull(int address) throws AddressErrorException { checkLoadWordAligned(address); if (inDataSegment(address)) { // 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)) { // 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)) { try { @@ -806,7 +732,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); } @@ -852,7 +778,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. @@ -862,31 +788,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); } /** * 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); } /** * 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); } diff --git a/src/rars/riscv/hardware/MemoryConfiguration.java b/src/rars/riscv/hardware/MemoryConfiguration.java index 8cb46eb9..11f19fd9 100644 --- a/src/rars/riscv/hardware/MemoryConfiguration.java +++ b/src/rars/riscv/hardware/MemoryConfiguration.java @@ -28,6 +28,9 @@ a copy of this software and associated documentation files (the (MIT license, http://www.opensource.org/licenses/mit-license.html) */ +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 +44,27 @@ 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, bss, stack, mmio, total; + public final Map sections; + public final int gp_offset, extern_size; - 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.configurationIdentifier = ident; this.configurationName = name; - this.configurationItemNames = items; - this.configurationItemValues = values; + text = sections.get(".text"); + data = sections.get(".data"); + bss = sections.get(".bss"); + 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() { @@ -65,75 +76,51 @@ public String getConfigurationName() { } public int[] getConfigurationItemValues() { - return configurationItemValues; + return null; } public String[] getConfigurationItemNames() { - return configurationItemNames; + return null; } 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 bss.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 bss.high; } public int getTextLimitAddress() { - return configurationItemValues[13]; - } - - public int getStackLimitAddress() { - return configurationItemValues[14]; - } - - public int getMemoryMapLimitAddress() { - return configurationItemValues[15]; + return text.high; } } \ No newline at end of file diff --git a/src/rars/riscv/hardware/MemoryConfigurations.java b/src/rars/riscv/hardware/MemoryConfigurations.java index 22a1d4cd..aa7cea0c 100644 --- a/src/rars/riscv/hardware/MemoryConfigurations.java +++ b/src/rars/riscv/hardware/MemoryConfigurations.java @@ -3,6 +3,7 @@ import rars.Globals; import java.util.ArrayList; +import java.util.HashMap; import java.util.Iterator; /* @@ -49,107 +50,49 @@ 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(".bss", 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(".bss", 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(".bss", 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("CompactDataAtZero", "Compact, Data 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())); + + // TODO: MAYBE this should be left + //setCurrentConfiguration(getConfigurationByName(Globals.getSettings().getMemoryConfiguration())); + // Iterator configurationsIterator = getConfigurationsIterator(); // while (configurationsIterator.hasNext()) { // MemoryConfiguration config = (MemoryConfiguration)configurationsIterator.next(); @@ -201,7 +144,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 +153,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..0a428911 --- /dev/null +++ b/src/rars/riscv/hardware/Range.java @@ -0,0 +1,18 @@ +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){ + return Integer.compareUnsigned(low,ptr) <= 0 && 0 <= Integer.compareUnsigned(high,ptr); + } + 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); + } +} \ 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..b20a0af8 100644 --- a/src/rars/simulator/ProgramArgumentList.java +++ b/src/rars/simulator/ProgramArgumentList.java @@ -153,7 +153,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(); // highest non-kernel address, sits "under" stack String programArgument; int[] argStartAddress = new int[programArgumentList.size()]; try { // needed for all memory writes @@ -168,8 +168,8 @@ public void storeProgramArguments() { argStartAddress[i] = highAddress + 1; } // 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) { + int stackAddress = Memory.configuration.getStackBaseAddress(); // base address for runtime stack. + if (highAddress < Memory.configuration.getStackBaseAddress()) { // 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 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..74e5409a 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)) { 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..eef37cb7 100644 --- a/src/rars/venus/DataSegmentWindow.java +++ b/src/rars/venus/DataSegmentWindow.java @@ -114,7 +114,7 @@ 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; @@ -178,13 +178,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 +322,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(), + Memory.configuration.getGlobalPointer(), + Memory.configuration.getStackBaseAddress(), + 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 +379,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 +391,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 +663,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. @@ -678,7 +683,8 @@ private void addButtonActionListenersAndInitialize() { 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. @@ -694,10 +700,10 @@ public void actionPerformed(ActionEvent ae) { 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); } @@ -707,7 +713,7 @@ public void actionPerformed(ActionEvent ae) { new ActionListener() { public void actionPerformed(ActionEvent ae) { userOrKernelMode = USER_MODE; - homeAddress = Memory.heapBaseAddress; + homeAddress =Memory.configuration.getHeapBaseAddress(); firstAddress = setFirstAddressAndPrevNextButtonEnableStatus(homeAddress); updateModelForMemoryRange(firstAddress); } @@ -717,7 +723,7 @@ public void actionPerformed(ActionEvent ae) { new ActionListener() { public void actionPerformed(ActionEvent ae) { userOrKernelMode = USER_MODE; - homeAddress = Memory.externBaseAddress; + homeAddress = Memory.configuration.getExternBaseAddress(); firstAddress = setFirstAddressAndPrevNextButtonEnableStatus(homeAddress); updateModelForMemoryRange(firstAddress); } @@ -727,7 +733,7 @@ public void actionPerformed(ActionEvent ae) { new ActionListener() { public void actionPerformed(ActionEvent ae) { userOrKernelMode = KERNEL_MODE; - homeAddress = Memory.memoryMapBaseAddress; + homeAddress = Memory.configuration.getMemoryMapBaseAddress(); firstAddress = homeAddress; firstAddress = setFirstAddressAndPrevNextButtonEnableStatus(firstAddress); updateModelForMemoryRange(firstAddress); @@ -738,7 +744,7 @@ public void actionPerformed(ActionEvent ae) { new ActionListener() { public void actionPerformed(ActionEvent ae) { userOrKernelMode = USER_MODE; - homeAddress = Memory.textBaseAddress; + homeAddress = Memory.configuration.getTextBaseAddress(); firstAddress = homeAddress; firstAddress = setFirstAddressAndPrevNextButtonEnableStatus(firstAddress); updateModelForMemoryRange(firstAddress); @@ -749,7 +755,7 @@ public void actionPerformed(ActionEvent ae) { 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,12 +780,8 @@ 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; + int lowLimit = Memory.configuration.total.low; + int highLimit = Memory.configuration.total.high; if (lowAddress <= lowLimit) { lowAddress = lowLimit; prevButton.setEnabled(false); 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/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); From 0603987803df18e2837cf65e3475c1639edb6469 Mon Sep 17 00:00:00 2001 From: Benjamin Landers Date: Fri, 21 Feb 2020 22:24:09 -0800 Subject: [PATCH 04/12] Remove unused kernel mode variable --- src/rars/venus/DataSegmentWindow.java | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/rars/venus/DataSegmentWindow.java b/src/rars/venus/DataSegmentWindow.java index eef37cb7..b5a5570b 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 @@ -116,7 +115,6 @@ public DataSegmentWindow(NumberDisplayBaseChooser[] choosers) { 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)); @@ -681,7 +679,6 @@ 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.configuration.getDataSegmentBaseAddress(), RegisterFile.getValue(RegisterFile.GLOBAL_POINTER_REGISTER)); @@ -698,7 +695,6 @@ 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.configuration.getDataSegmentBaseAddress(), RegisterFile.getValue(RegisterFile.STACK_POINTER_REGISTER)); // See comment above for gloButton... @@ -712,8 +708,7 @@ public void actionPerformed(ActionEvent ae) { heapButton.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent ae) { - userOrKernelMode = USER_MODE; - homeAddress =Memory.configuration.getHeapBaseAddress(); + homeAddress = Memory.configuration.getHeapBaseAddress(); firstAddress = setFirstAddressAndPrevNextButtonEnableStatus(homeAddress); updateModelForMemoryRange(firstAddress); } @@ -722,7 +717,6 @@ public void actionPerformed(ActionEvent ae) { extnButton.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent ae) { - userOrKernelMode = USER_MODE; homeAddress = Memory.configuration.getExternBaseAddress(); firstAddress = setFirstAddressAndPrevNextButtonEnableStatus(homeAddress); updateModelForMemoryRange(firstAddress); @@ -732,7 +726,6 @@ public void actionPerformed(ActionEvent ae) { mmioButton.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent ae) { - userOrKernelMode = KERNEL_MODE; homeAddress = Memory.configuration.getMemoryMapBaseAddress(); firstAddress = homeAddress; firstAddress = setFirstAddressAndPrevNextButtonEnableStatus(firstAddress); @@ -743,7 +736,6 @@ public void actionPerformed(ActionEvent ae) { textButton.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent ae) { - userOrKernelMode = USER_MODE; homeAddress = Memory.configuration.getTextBaseAddress(); firstAddress = homeAddress; firstAddress = setFirstAddressAndPrevNextButtonEnableStatus(firstAddress); @@ -754,8 +746,7 @@ public void actionPerformed(ActionEvent ae) { dataButton.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent ae) { - userOrKernelMode = USER_MODE; - homeAddress =Memory.configuration.getDataBaseAddress(); + homeAddress = Memory.configuration.getDataBaseAddress(); firstAddress = homeAddress; firstAddress = setFirstAddressAndPrevNextButtonEnableStatus(firstAddress); updateModelForMemoryRange(firstAddress); From c69b06d77d23e1ed240a956bfd7e47b9c30c8a38 Mon Sep 17 00:00:00 2001 From: Benjamin Landers Date: Fri, 21 Feb 2020 22:30:05 -0800 Subject: [PATCH 05/12] WIP: Fixed the issues in GUI and added config files for memory The problem with the addresss selector was that it used signed comparisons rather than unsigned. I moved the setting of the saved configuration into settings rather than memoryconfiguration because it prevents circular static dependency issues. The memory configuration setter now shows ranges for the various segments. Config files for memory configurations are now property files. I will put an example of on the wiki. --- src/rars/Globals.java | 2 + .../riscv/hardware/MemoryConfiguration.java | 8 --- .../riscv/hardware/MemoryConfigurations.java | 60 +++++++++++++------ src/rars/venus/DataSegmentWindow.java | 9 +-- .../SettingsMemoryConfigurationAction.java | 52 +++++++++++----- 5 files changed, 86 insertions(+), 45 deletions(-) diff --git a/src/rars/Globals.java b/src/rars/Globals.java index 759ad171..97fd2557 100644 --- a/src/rars/Globals.java +++ b/src/rars/Globals.java @@ -4,6 +4,7 @@ import rars.riscv.hardware.Memory; import rars.riscv.InstructionSet; import rars.riscv.SyscallNumberOverride; +import rars.riscv.hardware.MemoryConfigurations; import rars.util.PropertiesFile; import rars.venus.VenusUI; @@ -173,6 +174,7 @@ public static void initialize(boolean gui) { settings = new Settings(gui); initialized = true; debug = false; + MemoryConfigurations.setCurrentConfiguration(MemoryConfigurations.getConfigurationByName(settings.getMemoryConfiguration())); memory.clear(); // will establish memory configuration from setting } } diff --git a/src/rars/riscv/hardware/MemoryConfiguration.java b/src/rars/riscv/hardware/MemoryConfiguration.java index 11f19fd9..d368fdcd 100644 --- a/src/rars/riscv/hardware/MemoryConfiguration.java +++ b/src/rars/riscv/hardware/MemoryConfiguration.java @@ -75,14 +75,6 @@ public String getConfigurationName() { return configurationName; } - public int[] getConfigurationItemValues() { - return null; - } - - public String[] getConfigurationItemNames() { - return null; - } - public int getTextBaseAddress() { return text.low; } diff --git a/src/rars/riscv/hardware/MemoryConfigurations.java b/src/rars/riscv/hardware/MemoryConfigurations.java index aa7cea0c..5315f3a8 100644 --- a/src/rars/riscv/hardware/MemoryConfigurations.java +++ b/src/rars/riscv/hardware/MemoryConfigurations.java @@ -1,10 +1,9 @@ package rars.riscv.hardware; import rars.Globals; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; +import rars.util.Binary; +import java.io.InputStream; +import java.util.*; /* Copyright (c) 2003-2009, Pete Sanderson and Kenneth Vollmar @@ -82,24 +81,10 @@ public static void buildConfigurationCollection() { sections.put(".bss", 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("CompactDataAtZero", "Compact, Data at Address 0", sections,0x800,0x1000)); + 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(); - - // TODO: MAYBE this should be left - //setCurrentConfiguration(getConfigurationByName(Globals.getSettings().getMemoryConfiguration())); - - // Iterator configurationsIterator = getConfigurationsIterator(); - // while (configurationsIterator.hasNext()) { - // MemoryConfiguration config = (MemoryConfiguration)configurationsIterator.next(); - // if (currentConfigurationIdentifier.equals(config.getConfigurationIdentifier())) { - // setCurrentConfiguration(config); - // } - // } } } @@ -111,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); + } + public static MemoryConfiguration getConfigurationByName(String name) { Iterator configurationsIterator = getConfigurationsIterator(); while (configurationsIterator.hasNext()) { diff --git a/src/rars/venus/DataSegmentWindow.java b/src/rars/venus/DataSegmentWindow.java index b5a5570b..10345e32 100644 --- a/src/rars/venus/DataSegmentWindow.java +++ b/src/rars/venus/DataSegmentWindow.java @@ -324,8 +324,8 @@ private Point displayCellForAddress(int address) { Memory.configuration.getExternBaseAddress(), Memory.configuration.getDataBaseAddress(), Memory.configuration.getHeapBaseAddress(), - Memory.configuration.getGlobalPointer(), - Memory.configuration.getStackBaseAddress(), + -1, // GP + -1, // SP Memory.configuration.getTextBaseAddress(), Memory.configuration.getMemoryMapBaseAddress(), }; @@ -773,13 +773,14 @@ public void actionPerformed(ActionEvent ae) { private int setFirstAddressAndPrevNextButtonEnableStatus(int lowAddress) { int lowLimit = Memory.configuration.total.low; int highLimit = Memory.configuration.total.high; - if (lowAddress <= lowLimit) { + + 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/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()); } } From d1ab3a2372f2b62c0df9ed4a4ea9b2dcd2b7940c Mon Sep 17 00:00:00 2001 From: Benjamin Landers Date: Sun, 23 Feb 2020 22:53:12 -0800 Subject: [PATCH 06/12] Make Documentation just initialize normally --- src/rars/extras/Documentation.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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)); From e409d9dabff4b3906fd7705889c0e7f7452c2614 Mon Sep 17 00:00:00 2001 From: Benjamin Landers Date: Tue, 25 Feb 2020 20:18:40 -0800 Subject: [PATCH 07/12] Add resizing of memory to fix crash Because the limits on the size of segments weren't recalculated with respect to the blocks of memory, it was possible to cause an uncaught exception. That should no longer be possible. --- src/rars/riscv/hardware/Memory.java | 17 ++++++++++++----- src/rars/riscv/hardware/Range.java | 14 ++++++++++++++ 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/rars/riscv/hardware/Memory.java b/src/rars/riscv/hardware/Memory.java index 0d4a02a3..e1a53645 100644 --- a/src/rars/riscv/hardware/Memory.java +++ b/src/rars/riscv/hardware/Memory.java @@ -7,10 +7,7 @@ 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 @@ -230,7 +227,17 @@ public void clear() { */ public static void setConfiguration() { - configuration = MemoryConfigurations.getCurrentConfiguration(); + 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(".bss", t.bss); + 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()); } diff --git a/src/rars/riscv/hardware/Range.java b/src/rars/riscv/hardware/Range.java index 0a428911..313033c8 100644 --- a/src/rars/riscv/hardware/Range.java +++ b/src/rars/riscv/hardware/Range.java @@ -15,4 +15,18 @@ public Range combine(Range other){ 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 From 9c9c182a348ca29cc824725621196b11107e5fa6 Mon Sep 17 00:00:00 2001 From: Benjamin Landers Date: Tue, 3 Mar 2020 22:26:59 -0800 Subject: [PATCH 08/12] Save contents of loaded custom memory configurations --- src/rars/Globals.java | 7 +++++ src/rars/Settings.java | 26 +++++++++++++++++-- .../riscv/hardware/MemoryConfiguration.java | 21 ++++++++++++++- .../riscv/hardware/MemoryConfigurations.java | 2 +- 4 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/rars/Globals.java b/src/rars/Globals.java index 97fd2557..45098a92 100644 --- a/src/rars/Globals.java +++ b/src/rars/Globals.java @@ -4,10 +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; @@ -174,6 +176,11 @@ 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/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/riscv/hardware/MemoryConfiguration.java b/src/rars/riscv/hardware/MemoryConfiguration.java index d368fdcd..7b91fed1 100644 --- a/src/rars/riscv/hardware/MemoryConfiguration.java +++ b/src/rars/riscv/hardware/MemoryConfiguration.java @@ -28,6 +28,8 @@ 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; @@ -50,11 +52,15 @@ public class MemoryConfiguration { public final Range text, data, bss, stack, mmio, total; public final Map sections; public final int gp_offset, extern_size; - + public final boolean builtin; 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.builtin = builtin; text = sections.get(".text"); data = sections.get(".data"); bss = sections.get(".bss"); @@ -115,4 +121,17 @@ public int getTextLimitAddress() { 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(); + } } \ No newline at end of file diff --git a/src/rars/riscv/hardware/MemoryConfigurations.java b/src/rars/riscv/hardware/MemoryConfigurations.java index 5315f3a8..a898cea7 100644 --- a/src/rars/riscv/hardware/MemoryConfigurations.java +++ b/src/rars/riscv/hardware/MemoryConfigurations.java @@ -130,7 +130,7 @@ public static MemoryConfiguration loadNewConfig(InputStream is) { String ident = f.getProperty("ident"), name = f.getProperty("name"); if(ident == null || name == null) return null; - return new MemoryConfiguration(ident,name,ranges,gpint,externint); + return new MemoryConfiguration(ident,name,ranges,gpint,externint,false); } public static MemoryConfiguration getConfigurationByName(String name) { From 1fce5cf31731551941b847f9c23f9126ddd6f94e Mon Sep 17 00:00:00 2001 From: Benjamin Landers Date: Wed, 11 Mar 2020 22:05:13 -0700 Subject: [PATCH 09/12] Add option to use a memory config file in the cli --- src/rars/Launch.java | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/rars/Launch.java b/src/rars/Launch.java index e5dd9e9f..9fd424b4 100644 --- a/src/rars/Launch.java +++ b/src/rars/Launch.java @@ -11,10 +11,7 @@ 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; @@ -291,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); } @@ -702,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)."); From 354683dbc13572e05173d4ebd4478d6c98ebe91b Mon Sep 17 00:00:00 2001 From: Benjamin Landers Date: Wed, 11 Mar 2020 22:30:08 -0700 Subject: [PATCH 10/12] Revert change in renaming heap to bss It was a stretch to call it .bss and I was thinking about removing it entirely. So I think sticking with what is was previously called is better. --- src/rars/riscv/hardware/Memory.java | 5 ++--- src/rars/riscv/hardware/MemoryConfiguration.java | 8 ++++---- src/rars/riscv/hardware/MemoryConfigurations.java | 6 +++--- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/rars/riscv/hardware/Memory.java b/src/rars/riscv/hardware/Memory.java index e1a53645..b51302de 100644 --- a/src/rars/riscv/hardware/Memory.java +++ b/src/rars/riscv/hardware/Memory.java @@ -5,7 +5,6 @@ import rars.Settings; import rars.SimulationException; import rars.riscv.Instruction; -import rars.util.Binary; import java.util.*; @@ -232,7 +231,7 @@ public static void setConfiguration() { // 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(".bss", t.bss); + 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); @@ -271,7 +270,7 @@ public int allocateBytesFromHeap(int numBytes) throws IllegalArgumentException { if (newHeapAddress % 4 != 0) { newHeapAddress = newHeapAddress + (4 - newHeapAddress % 4); // next higher multiple of 4 } - if (newHeapAddress >= configuration.bss.high) { + if (newHeapAddress >= configuration.heap.high) { throw new IllegalArgumentException("request (" + numBytes + ") exceeds available heap storage"); } heapAddress = newHeapAddress; diff --git a/src/rars/riscv/hardware/MemoryConfiguration.java b/src/rars/riscv/hardware/MemoryConfiguration.java index 7b91fed1..3b0173fd 100644 --- a/src/rars/riscv/hardware/MemoryConfiguration.java +++ b/src/rars/riscv/hardware/MemoryConfiguration.java @@ -49,7 +49,7 @@ public class MemoryConfiguration { // Identifier is used for saving setting; name is used for display private String configurationIdentifier, configurationName; - public final Range text, data, bss, stack, mmio, total; + public final Range text, data, heap, stack, mmio, total; public final Map sections; public final int gp_offset, extern_size; public final boolean builtin; @@ -63,7 +63,7 @@ public MemoryConfiguration(String ident, String name, Map section this.builtin = builtin; text = sections.get(".text"); data = sections.get(".data"); - bss = sections.get(".bss"); + heap = sections.get("heap"); stack = sections.get("stack"); mmio = sections.get("mmio"); total = sections.values().stream().reduce(text, Range::combine); @@ -102,7 +102,7 @@ public int getDataBaseAddress() { } public int getHeapBaseAddress() { - return bss.low; + return heap.low; } public int getStackBaseAddress() { @@ -114,7 +114,7 @@ public int getMemoryMapBaseAddress() { } public int getDataSegmentLimitAddress() { - return bss.high; + return heap.high; } public int getTextLimitAddress() { diff --git a/src/rars/riscv/hardware/MemoryConfigurations.java b/src/rars/riscv/hardware/MemoryConfigurations.java index a898cea7..7bedb4d6 100644 --- a/src/rars/riscv/hardware/MemoryConfigurations.java +++ b/src/rars/riscv/hardware/MemoryConfigurations.java @@ -60,7 +60,7 @@ public static void buildConfigurationCollection() { // Default configuration comes from SPIM sections.put(".text", new Range( 0x400000,0x10000000)); sections.put(".data", new Range(0x10000000,0x10040000)); - sections.put(".bss", new Range(0x10040000,0x30000000)); + 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)); @@ -69,7 +69,7 @@ public static void buildConfigurationCollection() { // 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(".bss", new Range(0x2000,0x2800)); //Heap and stack split in half (ideally they should overlap) + 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)); @@ -78,7 +78,7 @@ public static void buildConfigurationCollection() { // 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(".bss", new Range(0x3000,0x3800)); //Heap and stack split in half (ideally they should overlap) + 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)); From f73bf33d55d3d458fed774cd8b88c36410c7a248 Mon Sep 17 00:00:00 2001 From: Benjamin Landers Date: Thu, 12 Mar 2020 23:45:09 -0700 Subject: [PATCH 11/12] Add length to Range.contains to fix bondary errors --- src/rars/riscv/hardware/Memory.java | 28 +++++++++++------------ src/rars/riscv/hardware/Range.java | 4 ++-- src/rars/tools/InstructionMemoryDump.java | 2 +- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/rars/riscv/hardware/Memory.java b/src/rars/riscv/hardware/Memory.java index b51302de..2279539f 100644 --- a/src/rars/riscv/hardware/Memory.java +++ b/src/rars/riscv/hardware/Memory.java @@ -299,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 - configuration.data.low; // relative to data segment start, in bytes oldValue = storeBytesInTable(dataBlockTable, relativeByteAddress, length, value); - } else if (configuration.stack.contains(address)) { + } 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 = 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 @@ -337,7 +337,7 @@ public int set(int address, int value, int length) throws AddressErrorException "Cannot write directly to text segment!", SimulationException.STORE_ACCESS_FAULT, address); } - } else if (configuration.mmio.contains(address)) { + } else if (configuration.mmio.contains(address,length)) { // memory mapped I/O. relativeByteAddress = address - configuration.mmio.low; oldValue = storeBytesInTable(memoryMapBlockTable, relativeByteAddress, length, value); @@ -502,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 - configuration.data.low; // relative to data segment start, in bytes value = fetchBytesFromTable(dataBlockTable, relativeByteAddress, length); - } else if (configuration.stack.contains(address)) { + } else if (configuration.stack.contains(address,length)) { // in stack. Similar to data, except relative address computed "backward" relativeByteAddress = configuration.stack.high - address; value = fetchBytesFromTable(stackBlockTable, relativeByteAddress, length); - } else if (configuration.mmio.contains(address)) { + } else if (configuration.mmio.contains(address,length)) { // memory mapped I/O. 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)) { @@ -590,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 - configuration.data.low) >> 2; // convert byte address to words value = fetchWordOrNullFromTable(dataBlockTable, relative); - } else if (configuration.stack.contains(address)) { + } else if (configuration.stack.contains(address,4)) { // in stack. Similar to data, except relative address computed "backward" 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) { @@ -794,7 +794,7 @@ public static boolean doublewordAligned(int address) { * false otherwise. */ public static boolean inTextSegment(int address) { - return configuration.text.contains(address); + return configuration.text.contains(address,4); } /** @@ -806,7 +806,7 @@ public static boolean inTextSegment(int address) { * false otherwise. */ public static boolean inDataSegment(int address) { - return configuration.data.contains(address); + return configuration.data.contains(address,4); } /** @@ -818,7 +818,7 @@ public static boolean inDataSegment(int address) { * false otherwise. */ public static boolean inMemoryMapSegment(int address) { - return configuration.mmio.contains(address); + return configuration.mmio.contains(address,4); } diff --git a/src/rars/riscv/hardware/Range.java b/src/rars/riscv/hardware/Range.java index 313033c8..f5f850d0 100644 --- a/src/rars/riscv/hardware/Range.java +++ b/src/rars/riscv/hardware/Range.java @@ -7,8 +7,8 @@ public Range(int low, int high){ this.high = high; this.low = low; } - public boolean contains(int ptr){ - return Integer.compareUnsigned(low,ptr) <= 0 && 0 <= Integer.compareUnsigned(high,ptr); + 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; diff --git a/src/rars/tools/InstructionMemoryDump.java b/src/rars/tools/InstructionMemoryDump.java index 74e5409a..ec43746e 100644 --- a/src/rars/tools/InstructionMemoryDump.java +++ b/src/rars/tools/InstructionMemoryDump.java @@ -174,7 +174,7 @@ protected void processRISCVUpdate(Observable resource, AccessNotice notice) { int a = m.getAddress(); // is a in the text segment (program)? - if (Memory.configuration.text.contains(a)) { + if (Memory.configuration.text.contains(a,m.getLength())) { if (notice.getAccessType() != AccessNotice.READ) return; if (a == lastAddress) return; lastAddress = a; From b5a4a3ec7c5a8065a9b833197c356cc00a05e408 Mon Sep 17 00:00:00 2001 From: Benjamin Landers Date: Fri, 8 May 2020 02:46:27 -0700 Subject: [PATCH 12/12] Fix program arguments issues One issue is that if no arguments were passed, the stack pointer could be pointing outside the stack. 2b15af6f removed the 4K buffer to the top of the stack, so this bug showed up now. Similarly it would caused an internal error when run with arguments because it would try to write to the byte just above the stack. Additionally, I changed the GUI to actually set the arguments for blank arguments so you get the desired stack (argc=0,argv={0}) Finally, I cleaned up a little --- src/rars/simulator/ProgramArgumentList.java | 22 +++++++++------------ src/rars/venus/run/RunGoAction.java | 3 +-- src/rars/venus/run/RunStepAction.java | 3 +-- 3 files changed, 11 insertions(+), 17 deletions(-) diff --git a/src/rars/simulator/ProgramArgumentList.java b/src/rars/simulator/ProgramArgumentList.java index b20a0af8..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.configuration.getStackBaseAddress(); // 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.configuration.getStackBaseAddress(); // base address for runtime stack. - if (highAddress < Memory.configuration.getStackBaseAddress()) { - // 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/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/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();