141 lines
4.8 KiB
C#
141 lines
4.8 KiB
C#
namespace CPUSimulation
|
|
{
|
|
public class MC // Memory Controller
|
|
{
|
|
|
|
MemoryBank[] _memoryBanks;
|
|
int _numberOfMemoryBanks;
|
|
int _memoryBankSize;
|
|
|
|
public MC(int numberOfMemoryBanks, int memoryBankSize = 1024)
|
|
{
|
|
_numberOfMemoryBanks = numberOfMemoryBanks;
|
|
_memoryBankSize = memoryBankSize;
|
|
Bit bit = new Bit();
|
|
Byte thisByte = new Byte(new Bit[8] { bit, bit, bit, bit, bit, bit, bit, bit });
|
|
|
|
_memoryBanks = new MemoryBank[numberOfMemoryBanks];
|
|
|
|
for(int i = 0; i < numberOfMemoryBanks; i++)
|
|
{
|
|
Byte[] newMemoryBank = new Byte[memoryBankSize];
|
|
for(int j = 0; j < memoryBankSize; j++)
|
|
{
|
|
newMemoryBank[j] = thisByte;
|
|
}
|
|
_memoryBanks[i] = new MemoryBank(newMemoryBank);
|
|
}
|
|
}
|
|
|
|
public string Read(Int16 address)
|
|
{
|
|
AddressOkay(address);
|
|
Byte[] byteData = new Byte[_numberOfMemoryBanks];
|
|
for (int i = 0; i < _numberOfMemoryBanks; i++)
|
|
{
|
|
byteData[i] = _memoryBanks[i].Read(new Address(address).ToString());
|
|
}
|
|
if (byteData.Length == 2)
|
|
{
|
|
return new Word(byteData).ToString();
|
|
}
|
|
else if (byteData.Length == 4)
|
|
{
|
|
return new DWord(new Word(byteData.Take(2).ToArray()), new Word(byteData.Skip(2).Take(2).ToArray())).ToString();
|
|
}
|
|
else if (byteData.Length == 8)
|
|
{
|
|
return new QWord(new DWord(new Word(byteData.Take(2).ToArray()), new Word(byteData.Skip(2).Take(2).ToArray())), new DWord(new Word(byteData.Skip(4).Take(2).ToArray()), new Word(byteData.Skip(6).Take(2).ToArray()))).ToString();
|
|
}
|
|
else
|
|
{
|
|
throw new ArgumentException($"Number of memory banks must be between 1 and 8 (inclusive).");
|
|
}
|
|
}
|
|
|
|
public void Write(Int16 address, Word data)
|
|
{
|
|
AddressOkay(address);
|
|
Byte[] byteData = data.GetBytes();
|
|
int byteCount = data.GetByteCount();
|
|
Byte[] bytesToWrite;
|
|
if (byteCount < _numberOfMemoryBanks)
|
|
{
|
|
bytesToWrite = GeneratePaddingBytes(byteData, byteCount);
|
|
}
|
|
else if (data.GetByteCount() > _numberOfMemoryBanks)
|
|
{
|
|
throw new ArgumentException($"Data must consist of {_numberOfMemoryBanks} bytes or less.");
|
|
}
|
|
else
|
|
{
|
|
bytesToWrite = byteData;
|
|
}
|
|
|
|
|
|
for (int i = 0; i < _numberOfMemoryBanks; i++)
|
|
{
|
|
_memoryBanks[i].Write(new Address(address).ToString(), bytesToWrite[i]);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public void Write(string address, string data)
|
|
{
|
|
if(address.Length != 16)
|
|
{
|
|
throw new ArgumentException("Address must be 16 bits long.");
|
|
}
|
|
if (data.Length % 8 != 0)
|
|
{
|
|
throw new ArgumentException("Data must be a multiple of 8 bits long.");
|
|
}
|
|
int byteCount = data.Length / 8;
|
|
if (byteCount > _numberOfMemoryBanks)
|
|
{
|
|
throw new ArgumentException($"Data must consist of {_numberOfMemoryBanks} bytes or less.");
|
|
}
|
|
if (byteCount < _numberOfMemoryBanks)
|
|
{
|
|
data = data.PadLeft(_numberOfMemoryBanks * 8, '0');
|
|
}
|
|
|
|
for (int i = 0; i < _numberOfMemoryBanks; i++)
|
|
{
|
|
string byteString = data.Substring(i * 8, 8);
|
|
Byte byteData = new Byte(byteString);
|
|
_memoryBanks[i].Write(address, byteData);
|
|
}
|
|
}
|
|
|
|
private void AddressOkay(Int16 address)
|
|
{
|
|
if (address < 0 || address >= _memoryBankSize)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(address), $"Received {address}. Address must be between 0 and {_memoryBankSize - 1}.");
|
|
}
|
|
}
|
|
|
|
private Byte[] GeneratePaddingBytes(Byte[] byteData, int byteCount)
|
|
{
|
|
Byte[] bytesToWrite;
|
|
int numberOfPaddingBytes = _numberOfMemoryBanks - byteCount;
|
|
bytesToWrite = new Byte[_numberOfMemoryBanks];
|
|
for (int i = 0; i < _numberOfMemoryBanks; i++)
|
|
{
|
|
if (i < numberOfPaddingBytes)
|
|
{
|
|
Bit bit = new Bit();
|
|
bytesToWrite[i] = new Byte(new Bit[8] { bit, bit, bit, bit, bit, bit, bit, bit });
|
|
}
|
|
else
|
|
{
|
|
bytesToWrite[i] = byteData[i - numberOfPaddingBytes];
|
|
}
|
|
}
|
|
|
|
return bytesToWrite;
|
|
}
|
|
}
|
|
} |