diff --git a/source/Cosmos.Core/IOPort.cs b/source/Cosmos.Core/IOPort.cs index fe3bcf0e77..77b54cea42 100644 --- a/source/Cosmos.Core/IOPort.cs +++ b/source/Cosmos.Core/IOPort.cs @@ -17,6 +17,15 @@ public static class IOPort [PlugMethod(PlugRequired = true)] public static void Write8(int aPort, byte aData) => throw null; + /// + /// Write many bytes to port with 400ns waits between each word + /// Plugged. + /// + /// A port to write to. + /// The data. + [PlugMethod(PlugRequired = true)] + public static void WriteMany8WithWait(int aPort, byte[] aData) => throw null; + /// /// Write Word to port. /// Plugged. @@ -69,16 +78,9 @@ public static class IOPort /// /// Output data array. /// Thrown if aData lenght is greater than Int32.MaxValue. - public static void Read8(int aPort, byte[] aData) - { - for (int i = 0; i < aData.Length / 2; i++) - { - var xValue = Read16(aPort); - aData[i * 2] = (byte)xValue; - aData[i * 2 + 1] = (byte)(xValue >> 8); - } - } - + [PlugMethod(PlugRequired = true)] + public static void Read8(int aPort, byte[] aData) => throw null; + /// /// Read Word from base port. /// diff --git a/source/Cosmos.Core_Asm/IOPortImpl.cs b/source/Cosmos.Core_Asm/IOPortImpl.cs index 08ad4abab2..4cdf274192 100644 --- a/source/Cosmos.Core_Asm/IOPortImpl.cs +++ b/source/Cosmos.Core_Asm/IOPortImpl.cs @@ -1,5 +1,6 @@ +using System.Security.Cryptography; using Cosmos.Core; - +using IL2CPU.API; using IL2CPU.API.Attribs; using XSharp; @@ -31,6 +32,37 @@ public override void AssembleNew(Assembler aAssembler, object aMethodInfo) #endregion + #region WriteMany8WithWait (many) + + private class WriteMany8WithWaitAssembler : AssemblerMethod { + public override void AssembleNew(Assembler aAssembler, object aMethodInfo) { + // the port index is in EBP+8 + // the reference to the byte array is in EBP+12 + XS.Set(XSRegisters.EDX, XSRegisters.EBP, sourceDisplacement: 16); // EDX = Port (ebp+16) + XS.Set(XSRegisters.ECX, XSRegisters.EBP, sourceDisplacement: 12); // ECX = Pointer to array (ebp+12) + + XS.Lea(XSRegisters.ESI, XSRegisters.ECX, sourceDisplacement: 16); // ESI = Data* (ecx+16) + XS.Set(XSRegisters.EBX, XSRegisters.ECX, sourceDisplacement: 8); // EBX = Length (ecx+8) + + XS.Label(".loop"); + XS.Set(XSRegisters.AX, XSRegisters.ESI, sourceIsIndirect: true); // ax = *esi + XS.WriteToPortDX(XSRegisters.AX); + XS.LiteralCode("out 0x80, al"); + XS.LiteralCode("out 0x80, al"); + XS.LiteralCode("out 0x80, al"); + XS.LiteralCode("out 0x80, al"); // Wait 400 ns between each word + XS.Add(XSRegisters.ESI, 2); // esi++ + + XS.Sub(XSRegisters.EBX, 2); // ebx-- + XS.Jump(XSharp.Assembler.x86.ConditionalTestEnum.NotZero, ".loop"); // if (ebx != 0) goto .loop + } + } + + [PlugMethod(Assembler = typeof(WriteMany8WithWaitAssembler))] + public static void WriteMany8WithWait(ushort aPort, byte[] aData) => throw null; + + #endregion + #region Write16 private class Write16Assembler : AssemblerMethod @@ -85,6 +117,35 @@ public override void AssembleNew(Assembler aAssembler, object aMethodInfo) #endregion + #region Read8 (many) + + private class Read8AssemblerMany : AssemblerMethod + { + public override void AssembleNew(Assembler aAssembler, object aMethodInfo) + { + // the port index is in EBP+16 + // the reference to the byte array is in EBP+12 + XS.Set(XSRegisters.EDX, XSRegisters.EBP, sourceDisplacement: 16); // EDX = Port (ebp+16) + XS.Set(XSRegisters.ECX, XSRegisters.EBP, sourceDisplacement: 12); // ECX = Pointer to array (ebp+12) + + XS.Lea(XSRegisters.ESI, XSRegisters.ECX, sourceDisplacement: 16); // ESI = Data* (ecx+16) + XS.Set(XSRegisters.EBX, XSRegisters.ECX, sourceDisplacement: 8); // EBX = Length (ecx+8) + + XS.Label(".loop"); + XS.ReadFromPortDX(XSRegisters.AX); + XS.Set(XSRegisters.ESI, XSRegisters.AX, destinationIsIndirect: true); // *esi = ax + XS.Add(XSRegisters.ESI, 2); // esi++ + + XS.Sub(XSRegisters.EBX, 2); // ebx-- + XS.Jump(XSharp.Assembler.x86.ConditionalTestEnum.NotZero, ".loop"); // if (ebx != 0) goto .loop + } + } + + [PlugMethod(Assembler = typeof(Read8AssemblerMany))] + public static void Read8(ushort aPort, byte[] aData) => throw null; + + #endregion + #region Read16 private class Read16Assembler : AssemblerMethod diff --git a/source/Cosmos.HAL2/BlockDevice/ATA_PIO.cs b/source/Cosmos.HAL2/BlockDevice/ATA_PIO.cs index cd68a40723..9207986131 100644 --- a/source/Cosmos.HAL2/BlockDevice/ATA_PIO.cs +++ b/source/Cosmos.HAL2/BlockDevice/ATA_PIO.cs @@ -405,7 +405,7 @@ public override void ReadBlock(ulong aBlockNo, ulong aBlockCount, ref byte[] aDa SelectSector(aBlockNo, aBlockCount); SendCmd(LBA48Bit ? Cmd.ReadPioExt : Cmd.ReadPio); IOPort.Read8(IO.Data, aData); - } + } /// /// Writes the specific block of data using the starting block, @@ -420,18 +420,9 @@ public override void WriteBlock(ulong aBlockNo, ulong aBlockCount, ref byte[] aD SelectSector(aBlockNo, aBlockCount); SendCmd(LBA48Bit ? Cmd.WritePioExt : Cmd.WritePio); - ushort xValue; - - for (long i = 0; i < aData.Length / 2; i++) - { - xValue = (ushort)((aData[i * 2 + 1] << 8) | aData[i * 2]); - IOPort.Write16(IO.Data, xValue); - Wait(); - // There must be a tiny delay between each OUTSW output word. A jmp $+2 size of delay. - // But that delay is cpu specific? so how long of a delay? - } + IOPort.WriteMany8WithWait(IO.Data, aData); - SendCmd(Cmd.CacheFlush); + SendCmd(Cmd.CacheFlush); } /// diff --git a/source/Cosmos.System2/FileSystem/FAT/FatFileSystem.cs b/source/Cosmos.System2/FileSystem/FAT/FatFileSystem.cs index 4b983455e0..40ba64c891 100644 --- a/source/Cosmos.System2/FileSystem/FAT/FatFileSystem.cs +++ b/source/Cosmos.System2/FileSystem/FAT/FatFileSystem.cs @@ -28,6 +28,11 @@ internal class Fat private readonly ulong mFatSector; + /// + /// A reused buffer for s read operations to save on allocations. + /// + private byte[] _getFatEntryReadBuffer; + /// /// Initializes a new instance of the class. /// @@ -43,6 +48,7 @@ public Fat(FatFileSystem aFileSystem, ulong aFatSector) mFileSystem = aFileSystem; mFatSector = aFatSector; + _getFatEntryReadBuffer = mFileSystem.NewBlockArray(); } /// @@ -133,9 +139,11 @@ public uint[] GetFatChain(uint aFirstEntry, long aDataSize = 0) if (xEntriesRequired > xReturn.Length) { long xNewClusters = xEntriesRequired - xReturn.Length; + uint prevFoundEntry = 0; for (int i = 0; i < xNewClusters; i++) { - xCurrentEntry = GetNextUnallocatedFatEntry(); + xCurrentEntry = GetNextUnallocatedFatEntry(prevFoundEntry); + prevFoundEntry = xCurrentEntry; mFileSystem.Write(xCurrentEntry, new byte[mFileSystem.BytesPerCluster]); uint xLastFatEntry = xReturn[xReturn.Length - 1]; SetFatEntry(xLastFatEntry, xCurrentEntry); @@ -175,12 +183,12 @@ public uint[] GetFatChain(uint aFirstEntry, long aDataSize = 0) /// Thrown on fatal error. /// Thrown on fatal error. /// Thrown when FAT type is unknown. - public uint GetNextUnallocatedFatEntry() + public uint GetNextUnallocatedFatEntry(uint startOffset = 0) { Global.Debugger.SendInternal("-- Fat.GetNextUnallocatedFatEntry --"); uint xTotalEntries = mFileSystem.FatSectorCount * mFileSystem.BytesPerSector / GetFatEntrySizeInBytes(); - for (uint i = mFileSystem.RootCluster + 1; i < xTotalEntries; i++) + for (uint i = mFileSystem.RootCluster + 1 + startOffset; i < xTotalEntries; i++) { GetFatEntry(i, out uint xEntryValue); if (xEntryValue == 0) // check if fat entry is free @@ -271,8 +279,8 @@ public void ClearAllFat() Global.Debugger.SendInternal($"RootCluster is {mFileSystem.RootCluster}"); Global.Debugger.SendInternal("Clearing all Fat Table"); - byte[] xFatTableFirstSector; - ReadFatSector(0, out xFatTableFirstSector); + byte[] xFatTableFirstSector = mFileSystem.NewBlockArray(); + ReadFatSector(0, ref xFatTableFirstSector); /* Change 3rd entry (RootDirectory) to be EOC */ SetValueInFat(2, FatEntryEofValue(), xFatTableFirstSector); @@ -311,10 +319,8 @@ public void ClearAllFat() /// Output data byte. /// Thrown when data lenght is greater then Int32.MaxValue. /// Thrown when data size invalid. - private void ReadFatSector(ulong aSector, out byte[] aData) - { + private void ReadFatSector(ulong aSector, ref byte[] aData) { Global.Debugger.SendInternal("-- FatFileSystem.ReadFatSector --"); - aData = mFileSystem.NewBlockArray(); ulong xSector = mFatSector + aSector; Global.Debugger.SendInternal("xSector =" + xSector); mFileSystem.Device.ReadBlock(xSector, mFileSystem.SectorsPerCluster, ref aData); @@ -364,7 +370,7 @@ internal void GetFatEntry(uint aEntryNumber, out uint aValue) ulong xSector = xEntryOffset / mFileSystem.BytesPerSector; Global.Debugger.SendInternal("xSector = " + xSector); - ReadFatSector(xSector, out byte[] xData); + ReadFatSector(xSector, ref _getFatEntryReadBuffer); switch (mFileSystem.mFatType) { @@ -372,7 +378,7 @@ internal void GetFatEntry(uint aEntryNumber, out uint aValue) // We now access the FAT entry as a WORD just as we do for FAT16, but if the cluster number is // EVEN, we only want the low 12-bits of the 16-bits we fetch. If the cluster number is ODD // we want the high 12-bits of the 16-bits we fetch. - uint xResult = BitConverter.ToUInt16(xData, (int)xEntryOffset); + uint xResult = BitConverter.ToUInt16(_getFatEntryReadBuffer, (int)xEntryOffset); if ((aEntryNumber & 0x01) == 0) { aValue = xResult & 0x0FFF; // Even @@ -384,12 +390,12 @@ internal void GetFatEntry(uint aEntryNumber, out uint aValue) break; case FatTypeEnum.Fat16: - aValue = BitConverter.ToUInt16(xData, (int)xEntryOffset); + aValue = BitConverter.ToUInt16(_getFatEntryReadBuffer, (int)xEntryOffset); break; case FatTypeEnum.Fat32: int localOffset = (int)(xEntryOffset % mFileSystem.BytesPerSector); - aValue = BitConverter.ToUInt32(xData, localOffset) & 0x0FFFFFFF; + aValue = BitConverter.ToUInt32(_getFatEntryReadBuffer, localOffset) & 0x0FFFFFFF; break; default: @@ -420,8 +426,8 @@ internal void SetFatEntry(ulong aEntryNumber, ulong aValue) ulong xSector = xEntryOffset / mFileSystem.BytesPerSector; int localOffset = (int)(xEntryOffset % mFileSystem.BytesPerSector); - byte[] xData; - ReadFatSector(xSector, out xData); + byte[] xData = mFileSystem.NewBlockArray(); + ReadFatSector(xSector, ref xData); switch (mFileSystem.mFatType) { @@ -442,6 +448,7 @@ internal void SetFatEntry(ulong aEntryNumber, ulong aValue) } WriteFatSector(xSector, xData); + GCImplementation.Free(xData); Global.Debugger.SendInternal("Returning from --- Fat.SetFatEntry ---"); } @@ -468,8 +475,8 @@ internal void SetFatEntry(ulong aEntryNumber, byte[] aData, uint aOffset, uint a ulong xSector = xEntryOffset / mFileSystem.BytesPerSector; ulong xSectorOffset = xSector * mFileSystem.BytesPerSector - xEntryOffset; - byte[] xData; - ReadFatSector(xSectorOffset, out xData); + byte[] xData = mFileSystem.NewBlockArray(); + ReadFatSector(xSectorOffset, ref xData); switch (mFileSystem.mFatType) { @@ -893,14 +900,13 @@ internal byte[] NewBlockArray() /// A data array to write the output to. /// Thrown when data lenght is greater then Int32.MaxValue. /// Thrown when data size invalid. - internal void Read(long aCluster, out byte[] aData) + internal void Read(long aCluster, ref byte[] aData) { Global.Debugger.SendInternal("-- FatFileSystem.Read --"); Global.Debugger.SendInternal($"aCluster = {aCluster}"); if (mFatType == FatTypeEnum.Fat32) { - aData = NewBlockArray(); long xSector = DataSector + (aCluster - RootCluster) * SectorsPerCluster; Global.Debugger.SendInternal($"xSector = {xSector}"); Device.ReadBlock((ulong)xSector, SectorsPerCluster, ref aData); @@ -908,7 +914,6 @@ internal void Read(long aCluster, out byte[] aData) else { Global.Debugger.SendInternal("aCluster: " + aCluster); - aData = Device.NewBlockArray(1); Device.ReadBlock((ulong)aCluster, RootSectorCount, ref aData); } Global.Debugger.SendInternal($"aData.Length = {aData.Length}"); @@ -957,21 +962,16 @@ internal void Write(long aCluster, byte[] aData, long aSize = 0, long aOffset = { aSize = BytesPerCluster; } - - byte[] xData; - Read(aCluster, out xData); - - - Array.Copy(aData, 0, xData, aOffset, aSize); + if (mFatType == FatTypeEnum.Fat32) { long xSector = DataSector + (aCluster - RootCluster) * SectorsPerCluster; - Device.WriteBlock((ulong)xSector, SectorsPerCluster, ref xData); + Device.WriteBlock((ulong)xSector, SectorsPerCluster, ref aData); } else { - Device.WriteBlock((ulong)aCluster, RootSectorCount, ref xData); + Device.WriteBlock((ulong)aCluster, RootSectorCount, ref aData); } } diff --git a/source/Cosmos.System2/FileSystem/FAT/FatStream.cs b/source/Cosmos.System2/FileSystem/FAT/FatStream.cs index e864ed625e..687fa325c6 100644 --- a/source/Cosmos.System2/FileSystem/FAT/FatStream.cs +++ b/source/Cosmos.System2/FileSystem/FAT/FatStream.cs @@ -2,7 +2,7 @@ using System; using System.IO; - +using Cosmos.Core; using Cosmos.System.FileSystem.FAT.Listing; namespace Cosmos.System.FileSystem.FAT @@ -280,12 +280,13 @@ public override int Read(byte[] aBuffer, int aOffset, int aCount) } long xClusterSize = mFS.BytesPerCluster; + byte[] xCluster = mFS.NewBlockArray(); while (xCount > 0) { long xClusterIdx = mPosition / xClusterSize; long xPosInCluster = mPosition % xClusterSize; - mFS.Read(mFatTable[(int)xClusterIdx], out byte[] xCluster); + mFS.Read(mFatTable[(int)xClusterIdx], ref xCluster); long xReadSize; if (xPosInCluster + xCount > xClusterSize) { @@ -394,6 +395,7 @@ public override void Write(byte[] aBuffer, int aOffset, int aCount) SetLength(xTotalLength); } + byte[] xCluster = mFS.NewBlockArray(); while (xCount > 0) { long xWriteSize; @@ -408,7 +410,7 @@ public override void Write(byte[] aBuffer, int aOffset, int aCount) xWriteSize = xCount; } - mFS.Read(mFatTable[xClusterIdx], out byte[] xCluster); + mFS.Read(mFatTable[xClusterIdx], ref xCluster); Array.Copy(aBuffer, aOffset, xCluster, (int)xPosInCluster, (int)xWriteSize); mFS.Write(mFatTable[xClusterIdx], xCluster); @@ -424,6 +426,8 @@ public override void Write(byte[] aBuffer, int aOffset, int aCount) aOffset += (int)xWriteSize; mPosition += xWriteSize; } + + GCImplementation.Free(xCluster); } } } diff --git a/source/Cosmos.System2/FileSystem/FAT/Listing/FatDiretoryEntry.cs b/source/Cosmos.System2/FileSystem/FAT/Listing/FatDiretoryEntry.cs index 881f4b187b..503302dcd0 100644 --- a/source/Cosmos.System2/FileSystem/FAT/Listing/FatDiretoryEntry.cs +++ b/source/Cosmos.System2/FileSystem/FAT/Listing/FatDiretoryEntry.cs @@ -903,8 +903,10 @@ private byte[] GetDirectoryEntryData() if (mEntryType != DirectoryEntryTypeEnum.Unknown) { - byte[] xData; - ((FatFileSystem)mFileSystem).Read(mFirstClusterNum, out xData); + FatFileSystem fatFS = mFileSystem as FatFileSystem; + + byte[] xData = fatFS.NewBlockArray(); + fatFS.Read(mFirstClusterNum, ref xData); Global.Debugger.SendInternal("-- --------------------------------------- --"); return xData; } @@ -1472,6 +1474,8 @@ internal static uint CalculateChecksum(string aShortName) private long GetDirectoryEntrySize(byte[] DirectoryEntryData) { long xResult = 0; + FatFileSystem fatFS = ((FatFileSystem)mFileSystem); + byte[] xDirData = fatFS.NewBlockArray(); for (uint i = 0; i < DirectoryEntryData.Length; i = i + 32) { @@ -1520,8 +1524,7 @@ private long GetDirectoryEntrySize(byte[] DirectoryEntryData) //Global.mFileSystemDebugger.SendInternal($"-- FatDirectoryEntry.GetDirectoryEntrySize() found directory: recursing!"); uint xFirstCluster = (uint)(BitConverter.ToUInt16(DirectoryEntryData, (int)i + 20) << 16 | BitConverter.ToUInt16(DirectoryEntryData, (int)i + 26)); - byte[] xDirData; - ((FatFileSystem)mFileSystem).Read(xFirstCluster, out xDirData); + fatFS.Read(xFirstCluster, ref xDirData); xResult += GetDirectoryEntrySize(xDirData); break; diff --git a/source/Cosmos.System2_Plugs/System/IO/FileImpl.cs b/source/Cosmos.System2_Plugs/System/IO/FileImpl.cs index 7fd237d0bd..57eb644bca 100644 --- a/source/Cosmos.System2_Plugs/System/IO/FileImpl.cs +++ b/source/Cosmos.System2_Plugs/System/IO/FileImpl.cs @@ -41,11 +41,9 @@ public static void WriteAllLines(string path, string[] contents) public static void WriteAllBytes(string path, byte[] aData) { - BinaryWriter Writer = new(new FileStream(path, FileMode.OpenOrCreate)); - - Writer.Write(aData); - - Writer.Dispose(); + var writer = new FileStream(path, FileMode.OpenOrCreate); + writer.Write(aData); + writer.Dispose(); } } } \ No newline at end of file