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