/// <summary> /// Injects code into the memory /// </summary> /// <param name="addr">Start address</param> /// <param name="code">Code to inject</param> /// <remarks>The code leaves the ROM area untouched.</remarks> public void InjectCodeToMemory(ushort addr, IReadOnlyCollection <byte> code) { foreach (var codeByte in code) { MemoryDevice.Write(addr++, codeByte); } }
/// <summary> /// Prepares the custom code for running, as if it were started /// with the RUN command /// </summary> public void PrepareRunMode() { // --- Set the keyboard in "L" mode var flags = MemoryDevice.Read(0x5C3B); flags |= 0x08; MemoryDevice.Write(0x5C3B, flags); }
/// <summary> /// Prepares the custom code for running, as if it were started /// with the RUN command /// </summary> public void PrepareRunMode(HashSet <string> options) { if (!options.Contains("cursork")) { // --- Set the keyboard in "L" mode var flags = MemoryDevice.Read(0x5C3B); flags |= 0x08; MemoryDevice.Write(0x5C3B, flags); } }
/// <summary> /// Prepares the custom code for running, as if it were started /// with the RUN command /// </summary> public void PrepareRunMode() { // --- Set the keyboard in "L" mode var flags = MemoryDevice.Read(0x5C3B); flags |= 0x08; MemoryDevice.Write(0x5C3B, flags); // --- Allow interrupts RunsInMaskableInterrupt = false; }
/// <summary> /// Clears the screep /// </summary> public void ClearScreen() { // --- Clear the screen for (var i = 0; i < 0x1800; i++) { MemoryDevice.Write((ushort)(0x4000 + i), 0x00); } for (var i = 0; i < 0x300; i++) { MemoryDevice.Write((ushort)(0x5800 + i), 0x38); } }
/// <summary> /// Injects code into the memory /// </summary> /// <param name="addr">Start address</param> /// <param name="code">Code to inject</param> /// <remarks>The code leaves the ROM area untouched.</remarks> public void InjectCodeToMemory(ushort addr, IReadOnlyCollection <byte> code) { // --- Clear the screen for (var i = 0; i < 0x1800; i++) { MemoryDevice.Write((ushort)(0x4000 + i), 0x00); } for (var i = 0; i < 0x300; i++) { MemoryDevice.Write((ushort)(0x5800 + i), 0x38); } // --- Now, inject the code foreach (var codeByte in code) { MemoryDevice.Write(addr++, codeByte); } }
/// <summary> /// Writes a byte to the memory /// </summary> /// <param name="addr">Memory address</param> /// <param name="value">Data byte</param> public void WriteSpectrumMemory(ushort addr, byte value) => MemoryDevice.Write(addr, value);
/// <summary> /// Loads an .srec into memory. /// Based on description at http://en.wikipedia.org/wiki/SREC_(file_format) /// </summary> /// <param name="stream">The stream to read the .srec from.</param> /// <returns>The number of words loaded.</returns> public uint LoadSrec(Stream stream) { StreamReader reader = new StreamReader(stream); uint wordsLoaded = 0; //Note: All hex values are big endian. //Read records while (!reader.EndOfStream) { string line = reader.ReadLine(); int index = 0; int checksum = 0; //Start code, always 'S' if (line[index++] != 'S') { throw new InvalidDataException("Expecting 'S'"); } //Record type, 1 digit, 0-9, defining the data field //0: Vendor-specific data //1: 16-bit data sequence //2: 24 bit data sequence //3: 32-bit data sequence //5: Count of data sequences in the file. Not required. //7: Starting address for the program, 32 bit address //8: Starting address for the program, 24 bit address //9: Starting address for the program, 16 bit address int recordType = Convert.ToInt32(line[index++].ToString(), 16); int addressLength = 0; switch (recordType) { case 0: case 1: case 5: case 9: addressLength = 2; break; case 2: case 8: addressLength = 3; break; case 3: case 7: addressLength = 4; break; default: throw new InvalidDataException("Unknown record type"); } //Byte count, 2 digits, number of bytes (2 hex digits) that follow (in address, data, checksum) int byteCount = Convert.ToInt32(line.Substring(index, 2), 16); index += 2; checksum += byteCount; //Address, 4, 6 or 8 hex digits determined by the record type for (int i = 0; i < addressLength; i++) { string ch = line.Substring(index + i * 2, 2); checksum += Convert.ToInt32(ch, 16); } int address = Convert.ToInt32(line.Substring(index, addressLength * 2), 16); index += addressLength * 2; byteCount -= addressLength; //Data, a sequence of bytes. byte[] data = new byte[byteCount - 1]; for (int i = 0; i < data.Length; i++) { data[i] = (byte)Convert.ToInt32(line.Substring(index, 2), 16); index += 2; checksum += data[i]; } //Checksum, two hex digits. Inverted LSB of the sum of values, including byte count, address and all data. int readChecksum = (byte)Convert.ToInt32(line.Substring(index, 2), 16); checksum = (~checksum & 0xFF); if (readChecksum != checksum) { throw new InvalidDataException("Failed Checksum!"); } //Put in memory Debug.Assert(data.Length % 4 == 0, "Data should only contain full 32-bit words."); switch (recordType) { case 3: //data intended to be stored in memory. List <uint> memContents = new List <uint>(); for (int i = 0; i < data.Length; i += 4) { uint val = 0; for (int j = i; j < i + 4; j++) { val <<= 8; val |= data[j]; } memContents.Add(val); } mAddressBus.IsWrite = true; for (int i = 0; i < memContents.Count; i++) { mDataBus.Write(memContents[i]); mAddressBus.Write((uint)(i + address)); RAM.Write(); ROM.Write(); wordsLoaded++; } break; case 7: //entry point for the program. CPU.PC = (uint)address; break; } } return(wordsLoaded); }