singrdk/base/Kernel/Singularity.Hal.Common/HalScreen.cs

328 lines
10 KiB
C#

///////////////////////////////////////////////////////////////////////////////
//
// Microsoft Research Singularity
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// File: HalScreen.cs
//
// Note:
// The Indispensable PC Hardware Book (Third Edition), pp1055-1066.
using System;
using System.Runtime.CompilerServices;
using Microsoft.Singularity.Channels;
using Microsoft.Singularity.Io;
using Microsoft.Singularity.Configuration;
namespace Microsoft.Singularity.Hal
{
// declare resources for the kernel manifest
[DriverCategory]
public sealed class HalScreenResources : DriverCategoryDeclaration
{
[IoFixedPortRange(Base = 0x03d4, Length = 0x01, Shared = true)]
public IoPortRange indexPort;
[IoFixedPortRange(Base = 0x03d5, Length = 0x01, Shared = true)]
public IoPortRange dataPort;
[IoFixedMemoryRange(Base = 0xb8000, Length = 8000, Shared = true)]
public IoMemoryRange screenMemory;
//[TODO] - how can we represent endpoints here?
//[ServiceEndpoint(typeof(ConsoleDeviceContract.Exp),
// CustomName = "HalScreen")]
//TRef<ServiceProviderContract.Exp:Start> conoutsp;
}
[CLSCompliant(false)]
public class HalScreen
{
public const int Columns = 80;
public const int Rows = 50;
public const int ScreenSize = Columns * Rows;
public const ushort CGA_INDEX_PORT = 0x3d4;
public const ushort CGA_DATA_PORT = 0x3d5;
public const byte SmallCursorStart = 6;
public const byte LargeCursorStart = 0;
private enum Coloring
{
Dim = 0x1700,
Yellow = 0x1e00,
Green = 0x1a00,
Red = 0x1c00,
Normal = 0x1f00
}
private ushort color = (ushort)Coloring.Normal;
private int cursor = 0;
private bool cursorVisible = false;
private byte cursorStartLine = SmallCursorStart;
private const byte CGA_CURSOR_START = 0xa;
private const byte CGA_CURSOR_MSB = 0xe;
private const byte CGA_CURSOR_LSB = 0xf;
private IoPort indexRegister = null;
private IoPort dataRegister = null;
private IoMemory screenBuffer = null;
public HalScreen(IoConfig config)
{
indexRegister =
((IoPortRange) config.FixedRanges[0]).PortAtOffset(
0, 1, Access.Write);
dataRegister =
((IoPortRange) config.FixedRanges[1]).PortAtOffset(
0, 1, Access.Write);
screenBuffer =
((IoMemoryRange) config.FixedRanges[2]).MemoryAtOffset(
0, ScreenSize * 2, Access.ReadWrite);
Clear();
WriteLine("Singularity HAL Console Driver.");
UpdateCursor(true);
}
public HalScreen()
{
// For compatibility with .csi compiled file
DebugStub.Break();
}
public void Dim()
{
color = (ushort)Coloring.Dim;
}
public void Yellow()
{
color = (ushort)Coloring.Yellow;
}
public void Green()
{
color = (ushort)Coloring.Green;
}
public void Red()
{
color = (ushort)Coloring.Red;
}
public void Normal()
{
color = (ushort)Coloring.Normal;
}
public void CursorFlash()
{
screenBuffer.Write16(0, (ushort)(screenBuffer.Read16(0) ^ 0xff00u));
}
public void CursorHide()
{
UpdateCursor(false);
}
public void CursorShow()
{
UpdateCursor(true);
}
[NoHeapAllocation]
public void Clear()
{
if (screenBuffer == null) {
DebugStub.Break();
return;
}
ushort zip = (ushort)(color | ' ');
IoResult result = screenBuffer.Write16NoThrow(0, zip, ScreenSize);
DebugStub.Assert(IoResult.Success == result);
cursor = 0;
UpdateCursor(cursorVisible);
}
[NoHeapAllocation]
public void GetDisplayDimensions(out int columns, out int rows)
{
columns = Columns;
rows = Rows;
}
[NoHeapAllocation]
public void GetCursorPosition(out int column, out int row)
{
column = cursor % Columns;
row = cursor / Columns;
}
[NoHeapAllocation]
public void SetCursorSizeLarge()
{
cursorStartLine = LargeCursorStart;
ForcedCursorUpdate();
}
[NoHeapAllocation]
public void SetCursorSizeSmall()
{
cursorStartLine = SmallCursorStart;
ForcedCursorUpdate();
}
[NoHeapAllocation]
private void ForcedCursorUpdate()
{
bool saved = cursorVisible;
cursorVisible = !cursorVisible;
UpdateCursor(saved);
}
[NoHeapAllocation]
private void UpdateCursor(bool newVisibleState)
{
IoResult result;
if (newVisibleState != cursorVisible) {
byte cgaStart = 32; // Cursor off
if (newVisibleState) {
cgaStart = (byte)(64 + cursorStartLine); // Cursor on
}
result = indexRegister.Write8NoThrow(CGA_CURSOR_START);
DebugStub.Assert(IoResult.Success == result);
result = dataRegister.Write8NoThrow(cgaStart);
DebugStub.Assert(IoResult.Success == result);
cursorVisible = newVisibleState;
}
if (newVisibleState) {
// Write cursor location
result = indexRegister.Write8NoThrow(CGA_CURSOR_MSB);
DebugStub.Assert(IoResult.Success == result);
result = dataRegister.Write8NoThrow((byte)(cursor >> 8));
DebugStub.Assert(IoResult.Success == result);
result = indexRegister.Write8NoThrow(CGA_CURSOR_LSB);
DebugStub.Assert(IoResult.Success == result);
result = dataRegister.Write8NoThrow((byte)(cursor & 0xff));
DebugStub.Assert(IoResult.Success == result);
}
}
[NoHeapAllocation]
public bool SetCursorPosition(int column, int row)
{
if (column < 0 || column >= Columns ||
row < 0 || row >= Rows) {
return false;
}
cursor = column + row * Columns;
UpdateCursor(cursorVisible);
return true;
}
[NoHeapAllocation]
public void ClearCursorToEndOfLine()
{
// Writing to the screen is slow. We might
// want to track how many characters are written per line
// to speed this up.
int column = cursor % Columns;
int row = cursor / Columns;
while (column != Columns) {
PutCharAt(' ', column++, row);
}
}
[NoHeapAllocation]
public bool PutCharAt(char c, int column, int row)
{
if (column < 0 || column >= Columns ||
row < 0 || row >= Rows) {
return false;
}
int offset = (column + row * Columns) * 2;
IoResult result = screenBuffer.Write16NoThrow(offset,
(ushort)(color | c));
DebugStub.Assert(IoResult.Success == result);
return true;
}
[NoHeapAllocation]
public void PutChar(char c)
{
PutChar((byte)c);
}
[NoHeapAllocation]
public void PutChar(byte c)
{
if (screenBuffer == null) {
return;
}
if (c == (byte)'\b') {
cursor--;
}
else if (c == (byte)'\r') {
int left = Columns - (cursor % Columns);
cursor -= cursor % Columns;
}
else if (c == (byte)'\n') {
cursor += Columns - (cursor % Columns);
}
else {
IoResult result =
screenBuffer.Write16NoThrow(cursor++ * 2,
(ushort)(color | (c & 0x7f)));
DebugStub.Assert(IoResult.Success == result);
}
if (cursor >= ScreenSize) {
IoResult result;
// Scroll up 1-line
result = screenBuffer.Copy8NoThrow(Columns * 2, 0,
(ScreenSize - Columns) * 2);
DebugStub.Assert(IoResult.Success == result);
// Blank bottom line
result =
screenBuffer.Write16NoThrow((ScreenSize - Columns) * 2,
(ushort)(color | ' '),
Columns);
DebugStub.Assert(IoResult.Success == result);
// Reel in cursor
cursor -= Columns;
}
UpdateCursor(cursorVisible);
}
[NoHeapAllocation]
public void Write(byte[] buffer, int offset, int count)
{
for (int i = 0; i < count; i++) {
PutChar(buffer[offset + i]);
}
}
private void WriteLine(String value)
{
for (int i = 0; i < value.Length; i++) {
PutChar((byte)value[i]);
}
PutChar((byte)'\r');
PutChar((byte)'\n');
}
}
} // namespace Microsoft.Singularity.Hal