diff --git a/Main/Basic/HiResTimer.cs b/Main/Basic/HiResTimer.cs new file mode 100644 index 0000000..06c6700 --- /dev/null +++ b/Main/Basic/HiResTimer.cs @@ -0,0 +1,236 @@ +/////////////////////////////////////////////////////////////////////////////// +// File: HiResTimer.cs +/////////////////////////////////////////////////////////////////////////////// +// Copyright (C) KGy SOFT, 2005-2019 - All Rights Reserved +// +// You should have received a copy of the LICENSE file at the top-level +// directory of this distribution. If not, then this file is considered as +// an illegal copy. +// +// Unauthorized copying of this file, via any medium is strictly prohibited. +/////////////////////////////////////////////////////////////////////////////// + + + +using System; +using System.Diagnostics; +using System.Threading; + +namespace KGySoft.CoreLibraries +{ + /// + /// Represents a high resolution timer that allows precise timing even with sub-milliseconds intervals. + /// The timer executes on a separated high priority thread. + /// + public class HiResTimer + { + /// + /// The number of ticks per one millisecond. + /// + private static readonly float tickFrequency = 1000f / Stopwatch.Frequency; + + private volatile float interval; + private volatile float ignoreElapsedThreshold = Single.PositiveInfinity; + private volatile bool isRunning; + + /// + /// Occurs when the elapses. + /// + public event EventHandler Elapsed; + + + /// + /// Gets or sets the interval, in milliseconds, before event is triggered. + /// Fractional values are allowed, too. When zero, the event is triggered as often as possible. + ///
Default value: 1.0, if initialized by the default constructor; otherwise, as specified in the constructor. + ///
+ /// + /// The interval in milliseconds. For example, 1000 represents one second and 0.001 represents one microsecond. + /// + /// is negative or . + /// + /// Please note that if is smaller than 16, then the timer may consume much CPU when running. + /// + public float Interval + { + get => interval; + set + { + if (value < 0f || Single.IsNaN(value)) + { + throw new ArgumentOutOfRangeException("This value is not allowed: " + value); + } + interval = value; + } + } + + /// + /// Gets or sets a threshold value, in milliseconds, to ignore an event (and thus trying to catch up the timer) + /// if the next invoke is late by the given value. Value must not be zero but fractions are allowed. + ///
Default value: +∞. + ///
+ /// + /// + /// If the value of this property is too low (smaller than the execution time of the event), it may + /// cause that the event is never triggered again. + /// + /// + /// is zero or negative or . + public float IgnoreElapsedThreshold + { + get => ignoreElapsedThreshold; + set + { + if (value <= 0f || Single.IsNaN(value)) + { + throw new ArgumentOutOfRangeException("This value is not allowed: " + value); + } + ignoreElapsedThreshold = value; + } + } + + /// + /// Gets or sets whether the event should be triggered. + ///
Default value: . + ///
+ /// + ///  if enabled; otherwise, . + /// + public bool Enabled + { + get => isRunning; + set + { + if (value) + Start(); + else + Stop(); + } + } + + /// + /// Initializes a new instance of the class with 1ms interval. + /// + public HiResTimer() : this(1f) + { + } + + /// + /// Initializes a new instance of the class with a specified . + /// + /// The time, in milliseconds, between events. Value must be non-negative. Fractional values are allowed. + /// is negative or . + public HiResTimer(float interval) + { + if (interval < 0f || Single.IsNaN(interval)) + { + throw new ArgumentOutOfRangeException("This value is not allowed: " + interval); + } + this.interval = interval; + } + + private static float ElapsedHiRes(Stopwatch stopwatch) => stopwatch.ElapsedTicks * tickFrequency; + + /// + /// Starts raising the event by enabling the timer. + /// + public void Start() + { + if (isRunning) + return; + + isRunning = true; + Thread thread = new Thread(ExecuteTimer) { Priority = ThreadPriority.Highest }; + thread.Start(); + } + + /// + /// Stops raising the event by disabling the timer. + /// + public void Stop() => isRunning = false; + + /// + /// The timer loop on a dedicated thread. + /// Works like an inverse SpinWait in terms of sleeping/spinning strategy: while SpinWait spins for short periods in the beginning and then starts to sleep, + /// this timer sleeps more often in the beginning (if there is enough time), and starts to spin just before triggering the next event. + /// + private void ExecuteTimer() + { + int fallouts = 0; + float nextTrigger = 0f; + + Stopwatch stopwatch = new Stopwatch(); + stopwatch.Start(); + + while (isRunning) + { + float intervalLocal = interval; + nextTrigger += intervalLocal; + float elapsed; + + while (true) + { + elapsed = ElapsedHiRes(stopwatch); + float diff = nextTrigger - elapsed; + if (diff <= 0f) + break; + + if (diff < 1f) + Thread.SpinWait(10); + else if (diff < 10f) + Thread.SpinWait(100); + else + { + // By default Sleep(1) lasts about 15.5 ms (if not configured otherwise for the application by WinMM, for example) + // so not allowing sleeping under 16 ms. Not sleeping for more than 50 ms so interval changes/stopping can be detected. + if (diff >= 16f) + Thread.Sleep(diff >= 100f ? 50 : 1); + else + { + Thread.SpinWait(1000); + Thread.Sleep(0); + } + + // if we have a larger time to wait, we check if the interval has been changed in the meantime + float newInterval = interval; + + // ReSharper disable once CompareOfFloatsByEqualityOperator + if (intervalLocal != newInterval) + { + nextTrigger += newInterval - intervalLocal; + intervalLocal = newInterval; + } + } + + if (!isRunning) + return; + } + + + float delay = elapsed - nextTrigger; + if (delay >= ignoreElapsedThreshold) + { + fallouts += 1; + continue; + } + + Elapsed?.Invoke(this, new HiResTimerElapsedEventArgs(delay, fallouts)); + fallouts = 0; + + // restarting the timer in every hour to prevent precision problems + if (stopwatch.Elapsed.TotalHours >= 1d) + { +#if NET35 + stopwatch.Reset(); + stopwatch.Start(); +#else + stopwatch.Restart(); +#endif + nextTrigger = 0f; + } + } + + stopwatch.Stop(); + } + } +} \ No newline at end of file diff --git a/Main/Basic/HiResTimerElapsedEventArgs.cs b/Main/Basic/HiResTimerElapsedEventArgs.cs new file mode 100644 index 0000000..5fb45c9 --- /dev/null +++ b/Main/Basic/HiResTimerElapsedEventArgs.cs @@ -0,0 +1,57 @@ +#region Copyright + +/////////////////////////////////////////////////////////////////////////////// +// File: HiResTimerElapsedEventArgs.cs +/////////////////////////////////////////////////////////////////////////////// +// Copyright (C) KGy SOFT, 2005-2019 - All Rights Reserved +// +// You should have received a copy of the LICENSE file at the top-level +// directory of this distribution. If not, then this file is considered as +// an illegal copy. +// +// Unauthorized copying of this file, via any medium is strictly prohibited. +/////////////////////////////////////////////////////////////////////////////// + +#endregion + +#region Usings + +using System; + +#endregion + +namespace KGySoft.CoreLibraries +{ + /// + /// Provides data for the HiResTimer.Elapsed event. + /// + public class HiResTimerElapsedEventArgs : EventArgs + { + #region Properties + + /// + /// Gets the delay, in milliseconds, of the triggering of the HiResTimer.Elapsed event + /// compared to when it should have been called. + /// + public float Delay { get; } + + /// + /// Gets the number of the fallen out HiResTimer.Enabled events since the last invoke. + /// The value is nonzero if a larger delay occurred than the value of the HiResTimer.IgnoreElapsedThreshold property + /// and thus one or more HiResTimer.Elapsed events were skipped to catch up the timer. + /// + public int Fallouts { get; } + + #endregion + + #region Constructors + + internal HiResTimerElapsedEventArgs(float delay, int fallouts) + { + Delay = delay; + Fallouts = fallouts; + } + + #endregion + } +} \ No newline at end of file diff --git a/Main/Basic/MultimediaTimer.cs b/Main/Basic/MultimediaTimer.cs deleted file mode 100644 index 4067f14..0000000 --- a/Main/Basic/MultimediaTimer.cs +++ /dev/null @@ -1,376 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using System.Diagnostics; - -namespace FoenixIDE.Timers -{ - // This code was added from a www source. - // Thanks to Laureano Lopez http://www.linkedin.com/in/lopezlaureano. - // Source: http://www.softwareinteractions.com/blog/2009/12/7/using-the-multimedia-timer-from-c.html - - - // Summary: - // Represents the method that will handle the - // System.Timers.MultimediaTimer.Elapsed event - // of a System.Timers.MultimediaTimer. - // - // Parameters: - // sender: - // The source of the event. - // - // e: - // An System.Timers.MultimediaElapsedEventHandler object that contains - // the event data. - public delegate void MultimediaElapsedEventHandler(object sender, - MultimediaElapsedEventArgs e); - - // Summary: - // Provides data for the System.Timers.Timer.Elapsed event. - public class MultimediaElapsedEventArgs : EventArgs - { - // Summary: - // Gets the time the System.Timers.Multimedia.Elapsed event was - // raised. - // - // Returns: - // The time the System.Timers.Multimedia.Elapsed event was raised. - public DateTime SignalTime { get; internal set; } - - internal MultimediaElapsedEventArgs() - { - SignalTime = DateTime.Now; - } - } - - // Summary: - // Generates recurring events in an application. - public class MultimediaTimer : IDisposable - { - //Lib API declarations - /// - /// Times the set event. - /// - /// The u delay. - /// The u resolution. - /// The lp time proc. - /// The dw user. - /// The fu event. - /// - [DllImport("Winmm.dll", CharSet = CharSet.Auto)] - private static extern uint timeSetEvent(uint uDelay, uint uResolution, - TimerCallback lpTimeProc, UIntPtr dwUser, uint fuEvent); - - /// - /// Times the kill event. - /// - /// The u timer ID. - /// - [DllImport("Winmm.dll", CharSet = CharSet.Auto)] - private static extern uint timeKillEvent(uint uTimerID); - - /// - /// Times the get time. - /// - /// - [DllImport("Winmm.dll", CharSet = CharSet.Auto)] - private static extern uint timeGetTime(); - - /// - /// Times the begin period. - /// - /// The u period. - /// - [DllImport("Winmm.dll", CharSet = CharSet.Auto)] - private static extern uint timeBeginPeriod(uint uPeriod); - - /// - /// Times the end period. - /// - /// The u period. - /// - [DllImport("Winmm.dll", CharSet = CharSet.Auto)] - private static extern uint timeEndPeriod(uint uPeriod); - - // Use this to pin the timerCallback functions to avoid improper garbage collection - private GCHandle _gcHandle; - - - /// - ///Timer type definitions - /// - [Flags] - public enum fuEvent : uint - { - /// - /// OneHzSignalEvent occurs once, after uDelay milliseconds. - /// - TIME_ONESHOT = 0, - /// - /// - /// - TIME_PERIODIC = 1, - /// - /// callback is function - /// - TIME_CALLBACK_FUNCTION = 0x0000, - - } - - /// - /// Delegate definition for the API callback - /// - private delegate void TimerCallback(uint uTimerID, uint uMsg, - UIntPtr dwUser, UIntPtr dw1, UIntPtr dw2); - - /// - /// The current timer instance ID - /// - private uint id = 0; - - /// - /// The callback used by the the API - /// - private TimerCallback timerCallback; - - - /// - /// Initializes a new instance of the System.Timers.MultimediaTimer - // class, and sets all the properties to their initial values. - /// - public MultimediaTimer() - { - Interval = 100; - AutoReset = true; - Enabled = false; - //Initialize the API callback - timerCallback = CallbackFunction; - // pin the timerCallback to a fixed memory address, such that the c# GC won't mess with it. - _gcHandle = GCHandle.Alloc(timerCallback); - } - - /// - /// Initializes a new instance of the System.Timers.MultimediaTimer - /// class, and sets the - /// System.Timers.MultimediaTimer.Interval property to the specified - /// time period. - /// - /// Parameters: - /// interval: - /// The time, in milliseconds, between events. - /// - /// Exceptions: - /// System.ArgumentException: - /// The value of the interval parameter is less than or equal to - /// zero, or greater than System.Int32.MaxValue. - /// - /// The interval. - public MultimediaTimer(uint interval) - { - Interval = interval; - AutoReset = true; - Enabled = false; - //Initialize the API callback - timerCallback = CallbackFunction; - _gcHandle = GCHandle.Alloc(timerCallback); - } - - - /// - /// Gets or sets a value indicating whether the - /// System.Timers.MultimediaTimer should raise - /// the System.Timers.MultimediaTimer.Elapsed event each time the - /// specified interval elapses - /// or only after the first time it elapses. - /// - /// Returns: - /// true if the System.Timers.MultimediaTimer should raise the - /// System.Timers.MultimediaTimer.Elapsed - /// event each time the interval elapses; false if it should raise - /// the System.Timers.MultimediaTimer.Elapsed - /// event only once, after the first time the interval elapses. The - /// default is true. - /// - /// true if [auto reset]; otherwise, false. - public bool AutoReset { get; set; } - - /// - /// Gets or sets a value indicating whether the - /// System.Timers.MultimediaTimer should raise - /// the System.Timers.MultimediaTimer.Elapsed event. - /// - /// Returns: - /// true if the System.Timers.MultimediaTimer should raise the - /// System.Timers.MultimediaTimer.Elapsed - /// event; otherwise, false. The default is false. - /// - /// - /// true if enabled; otherwise, false. - public bool Enabled { get; private set; } - - private object syncLock = new object(); - - /// - /// Gets or sets the interval at which to raise the - /// System.Timers.MultimediaTimer.Elapsed event. - /// - /// Returns: - /// The time, in milliseconds, between raisings of the - /// System.Timers.MultimediaTimer.Elapsed - /// event. The default is 100 milliseconds. - /// - /// Exceptions: - /// System.ArgumentException: - /// The interval is less than or equal to zero. - /// - /// The interval. - public uint Interval { get; set; } - - - /// - /// Occurs when the interval elapses. - /// - public event MultimediaElapsedEventHandler Elapsed; - - - /// - /// Releases the resources used by the System.Timers.MultimediaTimer. - /// - public void Close() - { - Dispose(); - } - - - /// - /// Starts raising the System.Timers.MultimediaTimer.Elapsed event by - /// setting System.Timers.MultimediaTimer.Enabled - /// to true. - /// - /// Exceptions: - /// System.ArgumentOutOfRangeException: - /// The System.Timers.MultimediaTimer is created with an interval - /// equal to or greater than - /// System.Int32.MaxValue + 1, or set to an interval less than zero. - /// - public void Start() - { - lock (syncLock) - { - //Kill any existing timer - Stop(); - Enabled = false; - - //Set the timer type flags - fuEvent f = fuEvent.TIME_CALLBACK_FUNCTION | (AutoReset ? - fuEvent.TIME_PERIODIC : fuEvent.TIME_ONESHOT); - - id = timeSetEvent(Interval, 0, timerCallback, UIntPtr.Zero, - (uint)f); - if (id == 0) - { - throw new Exception("timeSetEvent error"); - } - Debug.WriteLine("MultimediaTimer " + id.ToString() + " started"); - Enabled = true; - } - } - - - /// - /// Stops raising the System.Timers.MultimediaTimer.Elapsed event by - /// setting System.Timers.MultimediaTimer.Enabled - /// to false. - /// - public void Stop() - { - lock (syncLock) - { - if (id != 0) - { - timeKillEvent(id); - Debug.WriteLine("MultimediaTimer " + id.ToString() + " stopped"); - id = 0; - Enabled = false; - } - } - } - - /// - /// Called when [timer]. - /// - protected virtual void OnTimer() - { - Elapsed?.Invoke(this, new MultimediaElapsedEventArgs()); - } - - /// - /// CBs the func. - /// - /// The u timer ID. - /// The u MSG. - /// The dw user. - /// The DW1. - /// The DW2. - private void CallbackFunction(uint uTimerID, uint uMsg, UIntPtr dwUser, - UIntPtr dw1, UIntPtr dw2) - { - //Callback from the MultimediaTimer API that fires the Timer event. - // Note we are in a different thread here - OnTimer(); - } - - #region IDisposable Members - - private bool _disposed = false; - - - /// - /// Performs application-defined tasks associated with freeing, - /// releasing, or resetting unmanaged resources. - /// Releases all resources used by the current - /// System.Timers.MultimediaTimer. - /// - /// Parameters: - /// disposing: - /// true to release both managed and unmanaged resources; false to - /// release only - /// unmanaged resources. - /// - public void Dispose() - { - _gcHandle.Free(); - Dispose(true); - GC.SuppressFinalize(this); - } - - /// - /// Releases unmanaged and - optionally - managed resources - /// - /// true to release both managed and - /// unmanaged resources; false to release only unmanaged - /// resources. - private void Dispose(bool disposing) - { - if (!_disposed) - { - if (disposing) - { - Stop(); - } - } - _disposed = true; - } - - /// - /// Releases unmanaged resources and performs other cleanup operations - /// before the - /// is reclaimed by garbage collection. - /// - ~MultimediaTimer() - { - Dispose(false); - } - - #endregion - } -} diff --git a/Main/Devices/TimerRegister.cs b/Main/Devices/TimerRegister.cs index 5f30c2c..04c4325 100644 --- a/Main/Devices/TimerRegister.cs +++ b/Main/Devices/TimerRegister.cs @@ -1,15 +1,11 @@ -using FoenixIDE.Timers; +using KGySoft.CoreLibraries; using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace FoenixIDE.Simulator.Devices { public class TimerRegister : MemoryLocations.MemoryRAM { - private MultimediaTimer hiresTimer = null; + private HiResTimer hiresTimer = null; public delegate void RaiseInterruptFunction(); public RaiseInterruptFunction TimerInterruptDelegate; @@ -17,8 +13,8 @@ public class TimerRegister : MemoryLocations.MemoryRAM public TimerRegister(int StartAddress, int Length) : base(StartAddress, Length) { - hiresTimer = new MultimediaTimer(1000); - hiresTimer.Elapsed += new MultimediaElapsedEventHandler(Timer_Tick); + hiresTimer = new HiResTimer(1000); + hiresTimer.Elapsed += Timer_Tick; } public override void WriteByte(int Address, byte Value) @@ -51,8 +47,6 @@ public override void WriteByte(int Address, byte Value) { hiresTimer.Interval = adjInterval; } - - } } diff --git a/Main/Display/GPU_Common.cs b/Main/Display/GPU_Common.cs index e900614..fdfb1d7 100644 --- a/Main/Display/GPU_Common.cs +++ b/Main/Display/GPU_Common.cs @@ -158,6 +158,11 @@ public void SetTilesetBaseAddress(int val) TilesetBaseAddress = val; } + int SpriteBaseAddress; + public void SetSpriteBaseAddress(int val) + { + SpriteBaseAddress = val; + } private int[] GetTextLUT(byte fg, byte bg, bool gamma) { int[] values = new int[2]; @@ -444,18 +449,11 @@ private unsafe void DrawTiles(int* p, bool gammaCorrection, byte TextColumns, in { tilesetPointers[i] = VICKY.ReadLong(TilesetBaseAddress + i * 4) & 0x3F_FFFF; byte tilesetConfig = VICKY.ReadByte(TilesetBaseAddress + i * 4 + 3); - if (mode == 0) - { - strides[i] = (tilesetConfig & 8) != 0 ? strideLine : tileSize; - } - else - { - strides[i] = strideLine; - } + strides[i] = (tilesetConfig & 8) != 0 ? strideLine : tileSize; } for (int i = 0; i < tilemapItemCount; i++) { - byte tile = tiles[i * 2]; + byte tile = (byte)(tiles[i * 2]); byte tilesetReg = tiles[i * 2 + 1]; byte tileset = (byte)(tilesetReg & 7); //byte tileLUT = (byte)((tilesetReg & 0x38) >> 3); @@ -465,7 +463,7 @@ private unsafe void DrawTiles(int* p, bool gammaCorrection, byte TextColumns, in int strideX = strides[tileset]; if (strideX == tileSize) { - tilesetOffsets[i] = tilesetPointer + (tile % 16) * strideLine + (tile / 16) * strideLine * 16 + tileYOffset * tileSize; + tilesetOffsets[i] = tilesetPointer + (tile % 16) * tileSize * tileSize + (tile / 16) * tileSize * tileSize * 16 + tileYOffset * tileSize; } else { @@ -533,48 +531,72 @@ private unsafe void DrawTiles(int* p, bool gammaCorrection, byte TextColumns, in } } } - private unsafe void DrawSprites(int* p, bool gammaCorrection, byte layer, bool bkgrnd, int borderXSize, int borderYSize, int line, int width, int height) + const int screenOffset = 32; + private unsafe void DrawSprites(int* p, bool gammaCorrection, byte layer, bool bkgrnd, int borderXSize, int borderYSize, int line, int width, int height, bool dX, bool dY) { // There are 32 possible sprites to choose from. for (int s = 63; s > -1; s--) { - int addrSprite = MemoryMap.SPRITE_CONTROL_REGISTER_ADDR + s * 8 - VICKY.StartAddress; + int addrSprite = SpriteBaseAddress + s * 8; byte reg = VICKY.ReadByte(addrSprite); // if the set is not enabled, we're done. - byte spriteLayer = (byte)((reg & 0x70) >> 4); + byte spriteLayer = (mode == 0) ? ((byte)((reg & 0x70) >> 4)) : ((byte)((reg & 0x18) >> 3)); + // if the sprite is enabled and the layer matches, then check the line if ((reg & 1) != 0 && layer == spriteLayer) { - int posY = VICKY.ReadWord(addrSprite + 6) - 32; - if ((line >= posY && line < posY + 32)) + byte spriteSize = 32; + if (mode == 1) + { + switch ((reg & 0x60) >> 5) + { + case 1: + spriteSize = 24; + break; + case 2: + spriteSize = 16; + break; + case 3: + spriteSize = 8; + break; + } + } + int posY = VICKY.ReadWord(addrSprite + 6) - screenOffset; + int actualLine = dY ? line / 2 : line; + if ((actualLine >= posY && actualLine < posY + spriteSize)) { // TODO Fix this when Vicky II fixes the LUT issue - byte lutIndex = (byte)(((reg & 14) >> 1)); // 8 possible LUTs - int lutAddress = MemoryMap.GRP_LUT_BASE_ADDR - VICKY.StartAddress + lutIndex * 1024; + byte lutIndex = (mode == 0) ? (byte)(((reg & 0xC) >> 1)) : (byte)(((reg & 6) >> 1)); + + int lutAddress = lutBaseAddress + lutIndex * 1024; bool striding = (reg & 0x80) == 0x80; int spriteAddress = VICKY.ReadLong(addrSprite + 1) & 0x3F_FFFF; - int posX = VICKY.ReadWord(addrSprite + 4) - 32; + int posX = VICKY.ReadWord(addrSprite + 4) - screenOffset; + if (dX) + { + posX *= 2; + } - if (posX >= (width - borderXSize) || posY >= (height - borderYSize) || (posX + 32) < 0 || (posY + 32) < 0) + if (posX >= (width - borderXSize) || posY >= (height - borderYSize) || (posX + screenOffset) < 0 || (posY + screenOffset) < 0) { continue; } - int spriteWidth = 32; + int spriteWidth = spriteSize; int xOffset = 0; // Check for sprite bleeding on the left-hand-side if (posX < borderXSize) { xOffset = borderXSize - posX; posX = borderXSize; - spriteWidth = 32 - xOffset; + spriteWidth = spriteSize - xOffset; if (spriteWidth == 0) { continue; } } // Check for sprite bleeding on the right-hand side - if (posX + 32 > width - borderXSize) + if (posX + spriteSize > width - borderXSize) { spriteWidth = width - borderXSize - posX; if (spriteWidth == 0) @@ -586,19 +608,21 @@ private unsafe void DrawSprites(int* p, bool gammaCorrection, byte layer, bool b int clrVal = 0; byte pixVal = 0; - // Sprites are 32 x 32 - int sline = line - posY; + int sline = actualLine - posY; int lineOffset = line * STRIDE; int* ptr = p + lineOffset; for (int col = xOffset; col < xOffset + spriteWidth; col++) { // Lookup the pixel in the tileset - if the value is 0, it's transparent - pixVal = VRAM.ReadByte(spriteAddress + col + sline * 32); + pixVal = VRAM.ReadByte(spriteAddress + col + sline * spriteSize); if (pixVal != 0) { clrVal = GetLUTValue(lutIndex, pixVal, gammaCorrection); - //System.Runtime.InteropServices.Marshal.WriteInt32(p, (lineOffset + (col-xOffset + posX)) * 4, value); - ptr[col - xOffset + posX] = clrVal; + ptr[(dX ? col * 2: col) - xOffset + posX] = clrVal; + if (dX) + { + ptr[col * 2 +1 - xOffset + posX] = clrVal; + } } } } diff --git a/Main/Display/Gpu.Designer.cs b/Main/Display/Gpu.Designer.cs index 53da73e..7d87011 100644 --- a/Main/Display/Gpu.Designer.cs +++ b/Main/Display/Gpu.Designer.cs @@ -17,6 +17,13 @@ protected override void Dispose(bool disposing) { components.Dispose(); } + if (disposing && (components != null)) + { + BackgroundTextBrush.Dispose(); + BorderBrush.Dispose(); + CursorBrush.Dispose(); + InvertedBrush.Dispose(); + } base.Dispose(disposing); } diff --git a/Main/Display/Gpu.cs b/Main/Display/Gpu.cs index e4b7ce6..6e99e52 100644 --- a/Main/Display/Gpu.cs +++ b/Main/Display/Gpu.cs @@ -1,16 +1,9 @@ using System; -using System.Collections.Generic; -using System.ComponentModel; using System.Drawing; -using System.Text; using System.Windows.Forms; -using System.Drawing.Text; using System.Drawing.Imaging; -using FoenixIDE.Simulator.FileFormat; using FoenixIDE.MemoryLocations; -using System.Diagnostics; -using FoenixIDE.Timers; -using System.Threading.Tasks; +using KGySoft.CoreLibraries; namespace FoenixIDE.Display { @@ -24,7 +17,6 @@ public unsafe partial class Gpu : UserControl const int CHAR_WIDTH = 8; const int CHAR_HEIGHT = 8; - const int SPRITE_SIZE = 32; public MemoryRAM VRAM = null; public MemoryRAM VICKY = null; @@ -39,12 +31,8 @@ public unsafe partial class Gpu : UserControl public delegate void GpuUpdateFunction(); public GpuUpdateFunction GpuUpdated; - //Timer gpuRefreshTimer = new Timer - //{ - // Interval = 15 - //}; - // In debug mode, draw the screen twice per second, instead of 60 times. - private MultimediaTimer hiresTimer = new MultimediaTimer(500); + private HiResTimer hiresTimer; + private static readonly int[] vs = new int[256 * 8]; private int[] lutCache = vs; @@ -52,6 +40,8 @@ public Gpu() { InitializeComponent(); this.Load += new EventHandler(Gpu_Load); + hiresTimer = new HiResTimer(500); + hiresTimer.Elapsed += GpuRefreshTimer_Tick; } void Gpu_Load(object sender, EventArgs e) @@ -60,12 +50,9 @@ void Gpu_Load(object sender, EventArgs e) BlinkingCounter = BLINK_RATE; this.DoubleBuffered = true; - //gpuRefreshTimer.Tick += new EventHandler(GpuRefreshTimer_Tick); - hiresTimer.Elapsed += new MultimediaElapsedEventHandler(GpuRefreshTimer_Tick); if (DesignMode) { - //gpuRefreshTimer.Enabled = false; hiresTimer.Stop(); } else @@ -77,7 +64,6 @@ void Gpu_Load(object sender, EventArgs e) int sidemargin = ParentForm.Width - ClientRectangle.Width; ParentForm.Height = htarget + topmargin; ParentForm.Width = (int)Math.Ceiling(htarget * 1.6) + sidemargin; - //gpuRefreshTimer.Enabled = true; hiresTimer.Start(); } } @@ -88,7 +74,6 @@ void Gpu_Load(object sender, EventArgs e) /// private int BLINK_RATE = 30; private int BlinkingCounter; - void GpuRefreshTimer_Tick(object sender, EventArgs e) { if (BlinkingCounter-- == 0) @@ -103,6 +88,13 @@ void GpuRefreshTimer_Tick(object sender, EventArgs e) } } + public void StopTimer() + { + hiresTimer.Interval = 1000; + hiresTimer.Elapsed -= GpuRefreshTimer_Tick; + hiresTimer.Stop(); + } + public void SetRefreshPeriod(uint time) { BLINK_RATE = (int)(1000 / time /2); @@ -317,7 +309,7 @@ unsafe void Gpu_Paint(object sender, PaintEventArgs e) // Layer 12 - sprite layer 6 if ((MCRegister & 0x20) != 0) { - DrawSprites(bitmapPointer, gammaCorrection, 6, displayBorder, borderXSize, borderYSize, line, res.X, res.Y); + DrawSprites(bitmapPointer, gammaCorrection, 6, displayBorder, borderXSize, borderYSize, line, res.X, res.Y, false, false); } // Layer 11 - bitmap 1 if ((MCRegister & 0x8) == 0x8) @@ -327,7 +319,7 @@ unsafe void Gpu_Paint(object sender, PaintEventArgs e) // Layer 10 - sprite layer 5 if ((MCRegister & 0x20) != 0) { - DrawSprites(bitmapPointer, gammaCorrection, 5, displayBorder, borderXSize, borderYSize, line, res.X, res.Y); + DrawSprites(bitmapPointer, gammaCorrection, 5, displayBorder, borderXSize, borderYSize, line, res.X, res.Y, false, false); } // Layer 9 - tilemap layer 3 if ((MCRegister & 0x10) == 0x10) @@ -337,7 +329,7 @@ unsafe void Gpu_Paint(object sender, PaintEventArgs e) // Layer 8 - sprite layer 4 if ((MCRegister & 0x20) != 0) { - DrawSprites(bitmapPointer, gammaCorrection, 4, displayBorder, borderXSize, borderYSize, line, res.X, res.Y); + DrawSprites(bitmapPointer, gammaCorrection, 4, displayBorder, borderXSize, borderYSize, line, res.X, res.Y, false, false); } // Layer 7 - tilemap layer 2 if ((MCRegister & 0x10) == 0x10) @@ -347,7 +339,7 @@ unsafe void Gpu_Paint(object sender, PaintEventArgs e) // Layer 6 - sprite layer 3 if ((MCRegister & 0x20) != 0) { - DrawSprites(bitmapPointer, gammaCorrection, 3, displayBorder, borderXSize, borderYSize, line, res.X, res.Y); + DrawSprites(bitmapPointer, gammaCorrection, 3, displayBorder, borderXSize, borderYSize, line, res.X, res.Y, false, false); } // Layer 5 - tilemap layer 1 if ((MCRegister & 0x10) == 0x10) @@ -357,7 +349,7 @@ unsafe void Gpu_Paint(object sender, PaintEventArgs e) // Layer 4 - sprite layer 2 if ((MCRegister & 0x20) != 0) { - DrawSprites(bitmapPointer, gammaCorrection, 2, displayBorder, borderXSize, borderYSize, line, res.X, res.Y); + DrawSprites(bitmapPointer, gammaCorrection, 2, displayBorder, borderXSize, borderYSize, line, res.X, res.Y, false, false); } // Layer 3 - tilemap layer 0 if ((MCRegister & 0x10) == 0x10) @@ -367,7 +359,7 @@ unsafe void Gpu_Paint(object sender, PaintEventArgs e) // Layer 2 - sprite layer 1 if ((MCRegister & 0x20) != 0) { - DrawSprites(bitmapPointer, gammaCorrection, 1, displayBorder, borderXSize, borderYSize, line, res.X, res.Y); + DrawSprites(bitmapPointer, gammaCorrection, 1, displayBorder, borderXSize, borderYSize, line, res.X, res.Y, false, false); } // Layer 1 - bitmap layer 0 if ((MCRegister & 0x8) == 0x8) @@ -377,7 +369,7 @@ unsafe void Gpu_Paint(object sender, PaintEventArgs e) // Layer 0 - sprite layer 0 if ((MCRegister & 0x20) != 0) { - DrawSprites(bitmapPointer, gammaCorrection, 0, displayBorder, borderXSize, borderYSize, line, res.X, res.Y); + DrawSprites(bitmapPointer, gammaCorrection, 0, displayBorder, borderXSize, borderYSize, line, res.X, res.Y, false, false); } } else @@ -392,7 +384,7 @@ unsafe void Gpu_Paint(object sender, PaintEventArgs e) if ((MCRegister & 0x20) != 0) { - DrawSprites(bitmapPointer, gammaCorrection, 0, displayBorder, borderXSize, borderYSize, line, 320, BitmapY); + DrawSprites(bitmapPointer, gammaCorrection, 0, displayBorder, borderXSize, borderYSize, line, res.X, BitmapY, doubleX, doubleY); } if ((MCRegister & 0x8) != 0 || (MCRegister & 0x10) != 0) { @@ -421,7 +413,7 @@ unsafe void Gpu_Paint(object sender, PaintEventArgs e) } if ((MCRegister & 0x20) != 0) { - DrawSprites(bitmapPointer, gammaCorrection, 1, displayBorder, borderXSize, borderYSize, line, res.X, BitmapY); + DrawSprites(bitmapPointer, gammaCorrection, 1, displayBorder, borderXSize, borderYSize, line, res.X, BitmapY, doubleX, doubleY); } if ((MCRegister & 0x8) != 0 || (MCRegister & 0x10) != 0) { @@ -450,7 +442,7 @@ unsafe void Gpu_Paint(object sender, PaintEventArgs e) } if ((MCRegister & 0x20) != 0) { - DrawSprites(bitmapPointer, gammaCorrection, 2, displayBorder, borderXSize, borderYSize, line, res.X, BitmapY); + DrawSprites(bitmapPointer, gammaCorrection, 2, displayBorder, borderXSize, borderYSize, line, res.X, BitmapY, doubleX, doubleY); } if ((MCRegister & 0x8) != 0 || (MCRegister & 0x10) != 0) { @@ -479,7 +471,7 @@ unsafe void Gpu_Paint(object sender, PaintEventArgs e) } if ((MCRegister & 0x20) != 0) { - DrawSprites(bitmapPointer, gammaCorrection, 3, displayBorder, borderXSize, borderYSize, line, res.X, BitmapY); + DrawSprites(bitmapPointer, gammaCorrection, 3, displayBorder, borderXSize, borderYSize, line, res.X, BitmapY, doubleX, doubleY); } } } @@ -494,7 +486,10 @@ unsafe void Gpu_Paint(object sender, PaintEventArgs e) } if (!TileEditorMode) { - DrawMouse(bitmapPointer, gammaCorrection, line, res.X, res.Y); + if (mode == 0) + { + DrawMouse(bitmapPointer, gammaCorrection, line, res.X, res.Y); + } } } diff --git a/Main/FoenixIDE.csproj b/Main/FoenixIDE.csproj index 740dd5c..a13ca38 100644 --- a/Main/FoenixIDE.csproj +++ b/Main/FoenixIDE.csproj @@ -52,7 +52,8 @@ pdbonly true ..\bin\Release\ - TRACE + + prompt 4 false @@ -80,6 +81,8 @@ + + Component @@ -339,7 +342,6 @@ UploaderWindow.cs - ViewControl.cs diff --git a/Main/MemoryLocations/MemoryManager.cs b/Main/MemoryLocations/MemoryManager.cs index 19008e2..3cd0666 100644 --- a/Main/MemoryLocations/MemoryManager.cs +++ b/Main/MemoryLocations/MemoryManager.cs @@ -287,20 +287,13 @@ public void GetDeviceAt(int Address, out IMappable Device, out int DeviceAddress byte segment = (byte)(Address >> 13); // take the top 3 bits offset = MMU.GetPage((byte)(MMURegister & 3), segment) * 8192; // bits 4 and 5 of MMURegister determine which LUT is being edited - if (Address >= 8 && Address <= 0xF) + if ((MMURegister & 0x80) != 0 && Address >= 8 && Address <= 0xF) { Device = MMU; MMU.SetActiveLUT((byte)((MMURegister & 0x30) >> 4)); DeviceAddress = Address; return; } - if ((MMURegister & 0x80) != 0 && Address >= 0x10 && Address <= 0x2F) - { - Device = MMU; - MMU.SetActiveLUT((byte)((Address - 0x10)>>3)); - DeviceAddress = (Address & 7) + 8; - return; - } Device = RAM; offset = MMU.GetPage((byte)(MMURegister & 3), (byte)(Address >> 13)) * 8192; diff --git a/Main/Processor/CPU.cs b/Main/Processor/CPU.cs index 881085f..878e085 100644 --- a/Main/Processor/CPU.cs +++ b/Main/Processor/CPU.cs @@ -156,7 +156,7 @@ public bool ExecuteNext() } // TODO - if pc > RAM size, then throw an exception - CurrentOpcode = opcodes[MemMgr.RAM.ReadByte(PC)]; + CurrentOpcode = opcodes[MemMgr.ReadByte(PC)]; if (CurrentOpcode != null) { OpcodeLength = CurrentOpcode.Length; @@ -258,11 +258,11 @@ public int ReadSignature(int length, int pc) switch (length) { case 2: - return MemMgr.RAM.ReadByte(pc + 1); + return MemMgr.ReadByte(pc + 1); case 3: - return MemMgr.RAM.ReadWord(pc + 1); + return MemMgr.ReadWord(pc + 1); case 4: - return MemMgr.RAM.ReadLong(pc + 1); + return MemMgr.ReadLong(pc + 1); } return 0; diff --git a/Main/Properties/AssemblyInfo.cs b/Main/Properties/AssemblyInfo.cs index 684eb5e..1d4e3a8 100644 --- a/Main/Properties/AssemblyInfo.cs +++ b/Main/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.6.0.1")] -[assembly: AssemblyFileVersion("0.6.0.1")] +[assembly: AssemblyVersion("0.6.0.2")] +[assembly: AssemblyFileVersion("0.6.0.2")] diff --git a/Main/UI/AssetLoader.cs b/Main/UI/AssetLoader.cs index b68836c..850b680 100644 --- a/Main/UI/AssetLoader.cs +++ b/Main/UI/AssetLoader.cs @@ -177,10 +177,43 @@ private void StoreButton_Click(object sender, EventArgs e) { case ".png": Bitmap png = new Bitmap(FileNameTextBox.Text, false); + if (FileTypesCombo.SelectedIndex == 1) + { + if (png.Width == 16) + { + conversionStride = 16; + maxHeight = 256 * 16; + } + } + else if(FileTypesCombo.SelectedIndex == 2) + { + if (png.Width == 8) + { + conversionStride = 8; + maxHeight = 256 * 8; + } + } + ConvertBitmapToRaw(png, res, (byte)LUTCombo.SelectedIndex, conversionStride, maxHeight); break; case ".bmp": Bitmap bmp = new Bitmap(FileNameTextBox.Text, false); + if (FileTypesCombo.SelectedIndex == 1) + { + if (bmp.Width == 16) + { + conversionStride = 16; + maxHeight = 256 * 16; + } + } + else if (FileTypesCombo.SelectedIndex == 2) + { + if (bmp.Width == 8) + { + conversionStride = 8; + maxHeight = 256 * 8; + } + } ConvertBitmapToRaw(bmp, res, (byte)LUTCombo.SelectedIndex, conversionStride, maxHeight); break; default: @@ -250,6 +283,7 @@ private unsafe void ConvertBitmapToRaw(Bitmap bitmap, ResourceChecker.Resource r { } done = true; + // Reset the Lookup Table lut = new List(256) { @@ -397,6 +431,18 @@ private unsafe void ConvertBitmapToRaw(Bitmap bitmap, ResourceChecker.Resource r MemMgrRef.VICKY.WriteByte(lutBaseAddress + 4 * i, LowByte(rbg)); MemMgrRef.VICKY.WriteByte(lutBaseAddress + 4 * i + 1, MidByte(rbg)); MemMgrRef.VICKY.WriteByte(lutBaseAddress + 4 * i + 2, HighByte(rbg)); + MemMgrRef.VICKY.WriteByte(lutBaseAddress + 4 * i + 3, 0); + } + // if the Overwrite checkbox is checked, then complete with zeros + if (checkOverwriteLUT.Checked) + { + for (int i= lut.Count; i < 256; i++) + { + MemMgrRef.VICKY.WriteByte(lutBaseAddress + 4 * i, 0); + MemMgrRef.VICKY.WriteByte(lutBaseAddress + 4 * i + 1, 0); + MemMgrRef.VICKY.WriteByte(lutBaseAddress + 4 * i + 2, 0); + MemMgrRef.VICKY.WriteByte(lutBaseAddress + 4 * i + 3, 0); + } } } diff --git a/Main/UI/CPUWindow.cs b/Main/UI/CPUWindow.cs index 01d18db..5507204 100644 --- a/Main/UI/CPUWindow.cs +++ b/Main/UI/CPUWindow.cs @@ -436,7 +436,7 @@ public void RunButton_Click(object sender, EventArgs e) InterruptMatchesCheckboxes(); registerDisplay1.RegistersReadOnly(true); - MainWindow.Instance.setGpuPeriod(16); + MainWindow.Instance.setGpuPeriod(17); kernel.CPU.DebugPause = false; lastLine.Text = ""; kernel.CPU.CPUThread = new Thread(new ThreadStart(ThreadProc)); diff --git a/Main/UI/MainWindow.cs b/Main/UI/MainWindow.cs index 61d1361..c0a777e 100644 --- a/Main/UI/MainWindow.cs +++ b/Main/UI/MainWindow.cs @@ -203,6 +203,8 @@ private void BasicWindow_Load(object sender, EventArgs e) gpu.SetBitmapControlRegister(MemoryMap.BITMAP_CONTROL_REGISTER_ADDR - gpu.VICKY.StartAddress); gpu.SetTileMapBaseAddress(MemoryMap.TILE_CONTROL_REGISTER_ADDR - gpu.VICKY.StartAddress); gpu.SetTilesetBaseAddress(MemoryMap.TILESET_BASE_ADDR - gpu.VICKY.StartAddress); + + gpu.SetSpriteBaseAddress(MemoryMap.SPRITE_CONTROL_REGISTER_ADDR - gpu.VICKY.StartAddress); } else { @@ -229,6 +231,7 @@ private void BasicWindow_Load(object sender, EventArgs e) gpu.SetBitmapControlRegister(0xD100 - 0xC000); // IO Page 0 gpu.SetTileMapBaseAddress(0xD200 - 0xC000); gpu.SetTilesetBaseAddress(0xD280 - 0xC000); + gpu.SetSpriteBaseAddress(0xD900 - 0xC000); } if (disabledIRQs) @@ -336,13 +339,26 @@ private void ShowMemoryWindow() } else { + memoryWindow.Memory = kernel.CPU.MemMgr; memoryWindow.BringToFront(); } - memoryWindow.WriteMCRBytes += WriteMCRBytesToVicky; - memoryWindow.ReadMCRBytes += ReadMCRBytesFromVicky; + if (memoryWindow.WriteMCRBytes == null) + { + memoryWindow.WriteMCRBytes += WriteMCRBytesToVicky; + } + if (memoryWindow.ReadMCRBytes == null) + { + memoryWindow.ReadMCRBytes += ReadMCRBytesFromVicky; + } memoryWindow.UpdateMCRButtons(); - memoryWindow.SetGamma += UpdateGamma; - memoryWindow.SetHiRes += UpdateHiRes; + if (memoryWindow.SetGamma == null) + { + memoryWindow.SetGamma += UpdateGamma; + } + if (memoryWindow.SetHiRes == null) + { + memoryWindow.SetHiRes += UpdateHiRes; + } } public void SerialTransmitByte(byte Value) @@ -657,20 +673,6 @@ private void BasicWindow_KeyUp(object sender, KeyEventArgs e) private void ExitToolStripMenuItem_Click(object sender, EventArgs e) { - gpu.StartOfFrame = null; - gpu.StartOfLine = null; - if (debugWindow != null) - { - debugWindow.Close(); - } - if (memoryWindow != null) - { - memoryWindow.Close(); - } - if (GGF != null) - { - GGF.Close(); - } this.Close(); } @@ -713,6 +715,10 @@ private void Gpu_Update_Cps_Fps() previousFrame = currentFrame; Write_CPS_FPS_Safe("CPS: " + cps.ToString("N0"), "FPS: " + fps.ToString("N0")); } + else + { + Write_CPS_FPS_Safe("CPS: Stopped", "FPS: N/A"); + } WriteRTCTime(currentTime); } else @@ -853,8 +859,10 @@ private void DefaultKernelToolStripMenuItem_Click(object sender, EventArgs e) private void MainWindow_FormClosing(object sender, FormClosingEventArgs e) { + gpu.StopTimer(); gpu.StartOfFrame = null; gpu.StartOfLine = null; + ModeText.Text = "Shutting down CPU thread"; if (kernel.CPU != null) { @@ -865,6 +873,19 @@ private void MainWindow_FormClosing(object sender, FormClosingEventArgs e) kernel.CPU.CPUThread.Join(1000); } } + + if (debugWindow != null) + { + debugWindow.Close(); + } + if (memoryWindow != null) + { + memoryWindow.Close(); + } + if (GGF != null) + { + GGF.Close(); + } } private void MenuOpenExecutableFile_Click(object sender, EventArgs e) diff --git a/Main/UI/UploaderWindow.cs b/Main/UI/UploaderWindow.cs index 2377592..02608f7 100644 --- a/Main/UI/UploaderWindow.cs +++ b/Main/UI/UploaderWindow.cs @@ -3,16 +3,11 @@ using FoenixIDE.Simulator.FileFormat; using System; using System.Collections.Generic; -using System.ComponentModel; using System.Diagnostics; -using System.Drawing; using System.IO; using System.IO.Ports; -using System.Text; using System.Threading; -using System.Threading.Tasks; using System.Windows.Forms; -using Timer = System.Windows.Forms.Timer; namespace FoenixIDE.UI { @@ -47,6 +42,9 @@ public void SetBoardVersion(BoardVersion ver) case BoardVersion.RevUPlus: RevModeLabel.Text = "Mode: RevU+"; break; + case BoardVersion.RevJr: + RevModeLabel.Text = "Mode: F256Jr"; + break; } } @@ -267,6 +265,10 @@ private void SendBinaryButton_Click(object sender, EventArgs e) { BaseBankAddress = 0x18_0000; } + else if (boardVersion == BoardVersion.RevJr) + { + BaseBankAddress = 0; + } if (SendFileRadio.Checked) { @@ -625,7 +627,7 @@ private void SendData(byte[] buffer, int startAddress, int size) // DataBuffer = The buffer where the loaded Binary File resides // FnxAddressPtr = Pointer where to put the Data in the Fnx // i = Pointer Inside the data buffer - // Size_Of_File = Size of the Payload we want to transfer which ought to be smaller than 8192 + // Size_Of_File = Size of the Payload we want to transfer which ought to be smaller than 2048 bytes PreparePacket2Write(buffer, startAddress, 0, size); UploadProgressBar.Increment(size); } @@ -769,7 +771,16 @@ public void PreparePacket2Write(byte[] buffer, int FNXMemPointer, int FilePointe // Maximum transmission size is 8192 if (Size > 8192) { - Size = 8192; + if (boardVersion != BoardVersion.RevJr) + { + Size = 8192; + Console.WriteLine("PreparePacket2Write: output truncated to 8K bytes."); + } + else + { + Size = 2048; + Console.WriteLine("PreparePacket2Write: output truncated to 2K bytes."); + } } byte[] commandBuffer = new byte[8 + Size]; @@ -778,8 +789,8 @@ public void PreparePacket2Write(byte[] buffer, int FNXMemPointer, int FilePointe commandBuffer[2] = (byte)((FNXMemPointer >> 16) & 0xFF); // (H)24Bit Addy - Where to Store the Data commandBuffer[3] = (byte)((FNXMemPointer >> 8) & 0xFF); // (M)24Bit Addy - Where to Store the Data commandBuffer[4] = (byte)(FNXMemPointer & 0xFF); // (L)24Bit Addy - Where to Store the Data - commandBuffer[5] = (byte)((Size >> 8) & 0xFF); // (H)16Bit Size - How many bytes to Store (Max 8Kbytes for now) - commandBuffer[6] = (byte)(Size & 0xFF); // (L)16Bit Size - How many bytes to Store (Max 8Kbytes for now) + commandBuffer[5] = (byte)((Size >> 8) & 0xFF); // (H)16Bit Size - How many bytes to Store (Max 8Kbytes for now - 2K for Junior) + commandBuffer[6] = (byte)(Size & 0xFF); // (L)16Bit Size - How many bytes to Store (Max 8Kbytes for now - 2K for Junior) Array.Copy(buffer, FilePointer, commandBuffer, 7, Size); TxProcessLRC(commandBuffer); @@ -789,6 +800,10 @@ public void PreparePacket2Write(byte[] buffer, int FNXMemPointer, int FilePointe SendMessage(commandBuffer, null); // Tx the requested Payload Size (Plus Header and LRC), No Payload to be received aside of the Status. } + /** + * address: the address to read from, in the machine + * size: the number of bytes to read + */ public byte[] PreparePacket2Read(int address, int size) { if (size > 0) diff --git a/Main/roms/kernel_F256jr.hex b/Main/roms/kernel_F256jr.hex new file mode 100644 index 0000000..778e1c5 --- /dev/null +++ b/Main/roms/kernel_F256jr.hex @@ -0,0 +1,295 @@ +:20E000003F0D000D5245414459204445564943450044495200535441540052445300434CCF +:20E0200053004C495354004C4F41440044524956450052554E005359530048454C50000D8D +:20E0400054797065202768656C702720666F722068656C702E0D000D537570706F7274652D +:20E060006420636F6D6D616E64733A0D202020636C73202020202020202020436C656172DA +:20E0800073207468652073637265656E2E0D20202064726976652023202020202043686168 +:20E0A0006E6765732074686520647269766520746F20232E0D202020646972202020202058 +:20E0C00020202020446973706C61797320746865206469726563746F72792E0D2020206C1A +:20E0E0006F616422666E616D6522204C6F6164732074686520676976656E2066696C652014 +:20E10000272C31272E0D2020206C69737420202020202020204C4953547320646972656327 +:20E12000746F7269657320616E642073696D706C652070726F6772616D732E0D20202072B4 +:20E14000756E20202020202020202052756E73206C6F616465642070726F6772616D732ED2 +:20E160000D20202068656C70202020202020202053686F777320746869732068656C702EA6 +:20E180000D0D001EE035E211E06BE222E02EEE27E00EEF2CE04EE232E0C1F23AE0A0E10054 +:20E1A000A95785A5A9E085A64C16E7200BE7A9E085C4A03F209EE28000A90885C764C864C8 +:20E1C000C964CA64CB20DCE120F0E12002E290F8A000209EE280F1A90D4C9BE2A003209E2E +:20E1E000E2A920209BE2A5C70930209BE24CD7E1A200DA20CFFFFA9D0002E8C90DD0F34CC1 +:20E20000B9F918A200BC83E1F016E8E82024E2B00B2021E290032028E74CDCE1E8E880E598 +:20E22000607C83E184C3A00018B1C3F007C8D9FF01F0F53860A90C209BE21860B90002C9C8 +:20E2400020F006C90DF0051860C8D0F03860203CE2A909B00EB90002C938F008C939F004ED +:20E26000A9093860E93085C71880F8DA5AA29AA0E2A90120BDFFA900A6C7A00020BAFFA9AF +:20E2800000A201A00820D5FFB00D20B7FFF005A905388003202EEE7AFA60244CB9F984C3D5 +:0EE2A000A000B1C3F006209BE2C880F6186013 +:20E500000000010002000100030001000200010004000100020001000300010002000100E1 +:20E520000500010002000100030001000200010004000100020001000300010002000100BC +:20E5400006000100020001000300010002000100040001000200010003000100020001009B +:20E5600005000100020001000300010002000100040001000200010003000100020001007C +:20E5800007000100020001000300010002000100040001000200010003000100020001005A +:20E5A00005000100020001000300010002000100040001000200010003000100020001003C +:20E5C00006000100020001000300010002000100040001000200010003000100020001001B +:20E5E0000500010002000100030001000200010004000100020001000300010002000100FC +:20E600004F70656E4B45524E414C202D206120636C65616E2D726F6F6D20696D706C656D2C +:20E62000656E746174696F6E206F662074686520433634204B45524E414C204142490D433C +:20E640006F707972696768742032303232204A6573736965204F626572726575746572207C +:20E660003C476164676574404861636B7772656E63684C6162732E636F6D3E2E0D52656C49 +:20E68000656173656420756E646572207468652047504C33206C6963656E7365207769742C +:20E6A0006820746865206B65726E656C20657863657074696F6E3A0D6170706C696361746C +:20E6C000696F6E732077686963682073696D706C79207573652074686520414249206172E3 +:20E6E00065206E6F7420276465726976656420776F726B73272E0D00CB6020A6ED2018ED5F +:20E70000208CEC60E6A3D002E6A460A90085A5A9E685A64C16E7A000B1A5F00A20D2FFC83D +:20E72000D0F6E6A680F2186048A94A85A5A9E785A6A000B1A5F00620B9F9C880F668186998 +:20E740003020B9F9A90D20B9F9604572726F722000A0FFC8B1A5F00451A7F0F76064012030 +:20E7600037EC20FCED2081FF2084FF4C6EE7A200BD94E785A5E8BD94E785A6E8BD94E78595 +:20E78000A7E8BD94E785A8E82051E7D0037C94E7E8E880DCA6E704A0AFE7B2E70480BAE7CA +:20E7A000BDE700E0BEE743424D4241534943006C00A042415349433032004C0080004CAB69 +:20E7C000E1A5BB6005BB85BB60208DF3B0F66024BA300585B9C6BA6048A5B920CAF390034B +:20E7E00020C4E76885B96024BA1009A5B920D4F3B0D264BA6064BB64BA60C9109002A980DB +:20E80000604C8AF320F5E720FAE7B008094020DEF3B001604CC4E720E7E7B008A95F20F119 +:20E82000F3B001604CC4E720F5E720FAE7B008092020DEF3B001604CC4E720E7E7B008A9B7 +:20E840003F20F1F3B001604CC4E720FAE7B008096020DEF3B001604CC4E786A784A8AAA4AB +:20E86000B22080E8B01120B7FF0900D00B20EBE8B00620D2E8B0016020C4E71880F938605B +:20E88000A5AFD004A9083860A5B120B1FFB020A9F020DEF3B01920B1E8B01420AEFFB00FB5 +:20E8A000A5B120B4FFB008A9002096FFB0016018605AA000B1AD20C6E820A8FFB006C8C461 +:20E8C000AF90F1187A60C9619006C97BB0024920186020ABFFB013A5B120B1FFB00CA9E087 +:20E8E00020DEF3B00520AEFFB00060AAF002A202EA20A5FFB02185A520A5FFB01A85A6985B +:20E90000F008A5A585A7A5A685A8EA20A5FF900EC940F0154CC4E720C4E7A90438607C2F05 +:20E92000E9E6A7D002E6A890E218A6A7A4A86033E937E992A780EAD2A7F0E6A9103820142B +:20E94000E980E7A9028501AD00C01A8D00C080F7206CE9B008B94403D004A9033860B945A8 +:20E9600003C9089002A9080A0A0AAA60C90A9004A90138600A0A0AA86020B0E9485A48A046 +:20E9800000B99AE9F00620B9F9C880F56818693020B9F920A5E97A683860492F4F204552A5 +:20E9A000524F522000A90A20B9F9A90D20B9F96048DA5AA90D20B9F9A000B9440320D3E957 +:20E9C000C8982907D0F4A90D20B9F9C050D0EB7AFA6860484A4A4A4A20E6E968290F20E64F +:20E9E000E9A9204CB9F9AABDEDE94CB9F9303132333435363738396162636465660064C0A6 +:20EA000064C2A2009E4403E8E050D0F84C0FEAA900A200A0002032EA2040EAA200207EEA89 +:20EA2000A901A203A0002032EA2040EAA2012088EA6085B086B184B26085AF86AD84AE60D1 +:20EA4000A5B0206CE9B007B94403F005A9024C79E9A5B1994503A5B2994603A5B10A0A0A03 +:20EA6000AA20E5EBB0E8602050E990034C79E94CF0EBDA8A2050E990032079E9FA605A209D +:20EA800072EAB00286BC7A605A2072EAB00286BD7A6018605AA5BC2050E9B00320F0EBA5C8 +:20EAA000BD2050E9B00320F0EBA200207EEAA2012088EA187A60DA5AA5BC2050E9B00FB9DB +:20EAC0004503D00520D4EA800820E8EB90032079E97AFA60A5C0D01EA5E385C185C220D679 +:20EAE000EC900520F8E680F6C90DF0082038EB20B9F980EA85C0A4C1C4E3D00864C064C261 +:20EB0000A90D8026DAA601A9028501B1E5297F8601FAE6C1C92090DEC922F010A6C2D00AFD +:20EB2000C97BB006C961900249201860A5C264C2D002E6C2A92280F2DAA200DD4DEBF00871 +:20EB4000E8E8E00CD0F58003BD4EEBFA609601970599109A0E9B029C06DAA5BC2050E9B05A +:20EB60000520E8EB90032079E9FA090060DA5A48A5BD2050E990067A2079E9800668482006 +:20EB8000ECEB687AFA605AA900482050E9B00320F0EB681AC90AD0F1200FEA7A601BEC21DF +:20EBA000EC25EC1EECF3EBF3EBF3EBF3EBF3EBF3EBF3EBF3EB06EC0CEC10EC09ECF3EBF3B2 +:20EBC000EBF3EBF3EBF3EBF3EBF3EBF3EBF3EBF3EBF3EBF3EBF3EBF3EBF3EBF3EBF3EBF355 +:20EBE000EBF3EBF3EB7C9DEB187CA1EB387CA1EB7CA3EBA9054C79E9A9019944031860A9F9 +:20EC00000099440318604CF8EB4CFFEBA9001860B004A900186020B9F918604CF8EB4CFF7D +:20EC2000EBA9001860B00920D6EC9003A9001860A9074C79E91860A2027400E8E0A3D0F957 +:20EC40009C00019C0101A2009E0002E8E090D0F8A2009E0003E8E034D0F8A200A00818208E +:20EC60007AECA200A0A018206EEC6085B7609005A6B5A4B66086B584B6609005A6B3A4B4F9 +:20EC80006086B384B46060A2DCA000609C94039C95039C960360AD9603D004A9FF1860200F +:20ECA000CCFF789C94039C9503589C9603A9003860C903D0038D9603DA380878AE94039DA3 +:20ECC0003403CA1002A20FEC9503F0078E9403BADE010128FA60DAAE9503EC940338F00CDD +:20ECE000BD3403CA1002A20F8E950318FA604CE4F7A250A03C60B0032049F9A6E3A6E4601E +:20ED00007C00047C02047C04047C06047C08047C0A047C0C047C0E049C9703A9008004AAAE +:20ED2000203AED186910D0F7186038AE9703F00948BD00048D970368186048AD97039D0007 +:20ED4000048E970368186048DA5AA000B1A59D0004E8C8C010D0F57AFA6818609E00059EBA +:20ED6000010560480878BD0105990302989D01052868186048BC0005D02338BC0105F024B7 +:20ED80000878BC01059E010528B9030248BD0005990302989D00057AD0EFBC0005B903020D +:20EDA0009D00051868609C9803A990A820CCED186904D0F71860480878AC9803F00AB90357 +:20EDC000028D98032868186028683860480878AD98039903028C9803286818602CEE2CEEC8 +:20EDE0002CEE40EA67EA7EEA88EA92EAB6EA6DEB96EC59EB86EB2CEE5AE87EE848DAA20073 +:20EE0000BDDCED9D1403E8C920D0F5FA686086A584A6A000B00BB1A5991403C8C020D0F63C +:20EE200060B9140391A5C8C020D0F660386020D7E1DA5AA200A000A90185A5A90885A620E8 +:20EE40007EEE85AB207EEE05ABF03D207EEE85AB207EEE85AC208CEE207EEEF01C3006C903 +:20EE600020B011800DC99EF00280075AA036209EE27AA92020B9F980DF20D7E180C1B1A591 +:20EE8000C8D002E6A60900607AFA1860DA5A64C5A200A00020C6EE9008E6C5E820D5EE80F6 +:20EEA000F3A5C5F0098A18693020B9F9A200C8C8C00AD0E0A5C5D005A93020B9F9A9202070 +:20EEC000B9F97AFA1860A5ACD9E6EE9007D005A5ABD9E5EE6038A5ABF9E5EE85ABA5ACF900 +:20EEE000E6EE85AC601027E80364000A0001005052478FEF7072678FEF5047584CF07067EC +:20EF0000784CF050475AD2F070677AD2F00064C864C9203CE29001602037EFB019A5AFC9C3 +:20EF2000059010A5AF38E904A8B1ADC92ED004C84C5AEF4C8FEF60C85AB90002C922F00A99 +:20EF4000C90DF003C8D0F2387A6098BA38FD0101F0F5FAA00220BDFF1860A200BDEFEEF0C2 +:20EF60000E2073EF90068A6904AA80F07CF2EEA90438605A38B1AD5DEFEED011C8B1AD5D2B +:20EF8000F0EED009C8B1AD5DF1EED001187A60A001A5AFC901D009B2ADC924D0034C6BE245 +:20EFA000A900A6C7A00120BAFFA90020D5FFB0034CB4EF60A5A585C8A5A685C9A5A5C901DE +:20EFC000D049A5A6C908D04364C864C9A0002001F085AB2001F005ABF0312001F02001F0AB +:20EFE0002001F0F0E910F9C99ED0F52001F0C9309019C93AB01538E930200DF02001F08078 +:20F00000EDB1A5C8D002E6A6090060186048202AF02033F02033F0203EF02033F06885CA56 +:20F0200064CB203EF064CA64CB60A5C885CAA5C985CB60A5C80A85C8A5C92A85C96018A5F5 +:20F04000C865CA85C8A5C965CB85C960A900A6C7A00020BAFF20F5E72080E8B01920B7FF6E +:20F060000900D013207DF090084820D2E86838800620D2E8B001602028E71880F9A20020CA +:20F08000A5FFB023DDBAF0D035E8E004D0F1A20020A5FFB01295CC95C8E8E004D0F220A5A7 +:20F0A000FF90074940F00D4C28E7206FF2A2CC20C3F090EA18A6CCA4CD6050475800A9109A +:20F0C0003880E4F600D00AF601D006F602D002F60360A900A6C7A00020BAFF20F5E72080A9 +:20F0E000E8B01920B7FF0900D0132003F190084820D2E86838800620D2E8B001602028E78F +:20F100001880F9A902850120A5FFB065C95AF00AC97AF00CA910384C71F1A90385D48006CE +:20F12000A90485D48000A20074C874CC74D0E8E004D0F5A20020A5FFB04F800520A5FFB0F8 +:20F140003095CCE8E4D4D0F4A20020A5FFB02295D0E8E4D4D0F420A1F1D00DA200B5CC9572 +:20F16000C8E8E4D4D0F780CB20A5FF90074940F0A34C28E78D4FC0206FF2A2CC20C3F020C5 +:20F180008FF120A1F1D0E180AA4940D0E4186018A200B5D0E90095D0B005E8E004D0F318C4 +:20F1A00060A5D005D105D205D3600078A2FF9ABA8E9903ADAAF1D017EEAAF120F0F120160F +:20F1C000F2B0096401A93385004C5DE74C28E720E4F7A9E985A5A9F185A6A000B1A5F0066B +:20F1E00020B9F9C880F64CF6FF55706C6F616400A9802007F2A9902007F2A9A02007F2A9BA +:20F20000B02007F26400608500A2008A95089510E8E008D0F66020D9F22000F520FAE62058 +:20F22000E4F7B00A6401202FF220B8F7B00060201AFBA9498D0004A9F28D0104A900A00086 +:20F2400020D0F5A90020D8F5602030FB4C04E79C99034048DA5AA500640085D5A50185D6F9 +:20F260002097F5A5D68501A5D585007AFA6840DAA6CFD009A6CED00F92CC18FA60A902854B +:20F2800001EE4EC03880F480F424CE30F070EE48A5CC85D7A5CD291F09C085D8A5CD85D91C +:20F2A000A5CE06D92A06D92A06D92AA2048601A2908600850E6892D7A906850E6400188039 +:20F2C000BAA5C805C9F00BA5CA05CBD00520D6F21860A90438606CC8006401A9008D20D6C0 +:20F2E000A91A8D21D6A9018D22D62080F3A9038D20D6A92A8D21D6A9018D22D62080F3A914 +:20F30000018D20D6A9238D21D6A9018D22D62080F3A9078D20D6A92C8D21D6A9018D22D69C +:20F320002080F3A9028D20D6A9148D21D6A9018D22D62080F3A9028D20D6A9168D21D6A9EF +:20F34000018D22D62080F3A9458D20D6A9188D21D6A9018D22D62080F34C5CF36401A99FD4 +:20F360008D00D68D10D6A9BF8D00D68D10D6A9DF8D00D68D10D6A9FF8D00D68D10D6186025 +:20F38000AD22D62901C901F0F76085DA60A5DCF004A9403860DAA60164019701EE4FC064F9 +:20F3A00001A5A318690585DBAD81D64A900CA5DAA5A3C5DB90F2A502800CAD80D648AD819F +:20F3C000D6290485DC688601FA60DAA60164018D82D68027DAA60164018D83D6801D97010D +:20F3E0001701EE4EC06401DAA60164018D80D6800ADAA60164018D81D6800064DC200FF494 +:20F40000AD81D6291018F00338A9808601FA60A9322017F43AD0FA2020F4201DF42020F4BF +:09F420002023F4EAEAEAEAEA60BA +:20F50000486401A9FF8D6CD68D6DD68D68D68D69D6AD60D68D60D6AD61D68D61D6A9368DA6 +:20F520000204A9F58D0304A902A000999A03C8C010D0F858681860A0028401484A4A4A4AE3 +:20F54000A8B954F58D20C068290FA8B954F58D21C064016030313233343536373839616247 +:20F560006364656600485AA0028401484A4A4A4AA8B986F58D22C068290FA8B986F58D2349 +:20F58000C064017A686030313233343536373839616263646566006401AE60D6F011BC009C +:20F5A000E5B9C8F58D60D6BE9A032000ED80E86401AE61D6F011BC00E5B9C8F58D61D6BE79 +:20F5C000A2032000ED80E8600102040810204080C010B003999A0360C910B00DDA20EAF52A +:20F5E00049FF3D6CD69D6CD6FA60A2008908F001E829075AA8B9C8F57A60C910B00BDA20EF +:20F60000EAF51D6CD69D6CD6FA6052F7B6F7B6F7EEF699F79EF730F793F7202AEDB0092006 +:20F6200029F69004203AED3860A90220FAF5A90320FAF5A9AC208EF6A9A7208EF620A0F620 +:20F64000B02B206EF6B026A9AA20AEF6B01FC95538D01A206EF6B015BD05050904207CF6A0 +:20F66000B00BA90A85A5A9F685A62047ED60A92020AEF6B0F829BC290F4C7CF648A96020F3 +:20F680008EF668B0082097F6B0039D05056020C1F6B0038D44D66020C1F6B0038D40D66041 +:20F6A000A06420B4F6B00588D0F838601860208EF690016020BDF6B003AD40D660A90180FF +:20F6C0000848A90220C9F668609D0705A5A39D080518AD44D649023D0705F00160A5A338A9 +:20F6E000FD0805C91EB0F520F8E680E680FE205CED9E0905A9FF9D02058AA00420D0F5A975 +:20F70000A88D55D6A9618D56D6A9008D57D69C51D69C52D69C53D6A9028D54D6A9648D1902 +:20F72000D09C1AD0A9018D18D0A90420D8F518605A20B6ED90027A609901026899000220FA +:20F7400063EDFE0205D003204CF71860A90D8D50D660AD44D68902D021BD0A05BC0905D034 +:20F76000132074EDB017DE0205B90002D010B9010220CCED8D40D69E0905204CF760A9D48A +:20F780008D44D69D0905B901029D0A0520CCED80E980BFA90420FAF560AD40D61860B9B26C +:20F7A000F71D0505207CF6B008B9B4F7208EF6B000600102AEA818606401201AF6B024206F +:20F7C00009EDB01FDA8AA002203AFCB0032009EDFAB010DA8AA003203AFCB0032009EDFA65 +:20F7E000B001186020F2F7A9E685E764E82014F9186064019C00D09C01D0A9018D00D02086 +:20F800000FF820A8F820B5F82060F89C10D060A200BD20F89D00D89D40D8E8E040D0F26035 +:20F8200000000000FFFFFF0000008800EEFFAA00CC44CC0055CC0000AA00000077DDDD00D4 +:20F840005588DD00004466007777FF00333333007777770066FFAA00FF880000BBBBBB0092 +:20F86000DA5AA401A901850164E5A9D085E6A200208AF8E8A5E5690485E5D0F4A5E61A85D7 +:20F88000E6C9E0D0EB84017AFA605AA003A9FF209EF88A883005209EF880F87A1860482992 +:20F8A000E091E5680A0A0A609C04D09C07D09C06D09C05D060A50148A901850120C4F86884 +:20F8C00085011860DA5A64DD64DFA9C085DEA9C485E0A204A000A701B1DD27014A91DD492F +:20F8E000FF91DFC8D0F0E6DEE6E0CAD0E97AFA60DA5AA000A6E2F015B1DD91DFC8D0F9E65A +:20F90000DEE6E0CAD0F28005B1DD91DFC8C4E1D0F77AFA6048DA5AA9028501A9202034F969 +:20F92000A9038501A5E72034F9A200A0002049F97AFA686064E5A0C084E6A214A00091E5FD +:20F94000C8D0FBE6E6CAD0F66086E384E464E698C03C9002A03B0A0A26E665E49002E6E675 +:20F960000A26E60A26E60A26E60A26E685E5A5E669C085E6A50148A90285012082F96885FF +:20F980000160A4E3A2038601B1E564018D13D0A2028601B1E5498064018D12D0A5E38D1461 +:20F9A000D09C15D0A5E48D16D09C17D0A90B8D10D09C11D0A20286016048DA5AA601DAA2AF +:20F9C00002860120D4F9A6E3A4E42049F9FA86017AFA6860A6E3A4E4482049F968C92090E5 +:20F9E00007C980B03A4CBAFAC905F033C9119007C91BD02B4C63FA0AAA7CFCF91EFA91FA1B +:20FA00006CFA1EFA1EFA94FA73FAADFAA3FAAEFA53FAD0FA64FA54FA84FA1EFA7CFA60A298 +:20FA200000DD33FAF00AE8E8E8E018D0F44CF3FA7C34FA1184FA124BFA1367FA14A3FA1D43 +:20FA400073FA9153FA9250FA9314F9A28086E86064E8606064E3A4E4C8C03CD0034CDCFA5B +:20FA600084E460604C14F964E364E460A5E3F002C6E360A5E3C94FB002E6E360A5E43A3025 +:20FA80000285E460A5E41AC93CD0034CDCFA85E46064E360A05088F006B1E5C920F0F78436 +:20FAA000E380D0206CFAA4E3A92091E56060A92020BAFAA5E32903D0F560A4E305E891E5A7 +:20FAC000E601A5E791E5C601C8C050F08784E360A4E3A92091E5C8C050D0F960A9C085DECD +:20FAE00085E0A95085DD64DFA9C085E1A91285E24CF0F8A200DD0AFBF006E8E010D0F66066 +:20FB00008A0A0A0A0A090685E76090051C9F9C1E1F9E8195969798999A9B6401A9FF8D034B +:20FB2000DCA9008D02DCA9FFA20795E9CA10FB606401A97FA2008D01DC8DAA03AD00DC8DE8 +:20FB4000AB0355E9F0032053FBE8ADAA034A0980B0E460A8B900E58DAC03A8B9C8F549FF67 +:20FB600035E995E9B9C8F52DAB03D00548207DFB6815E995E9ADAB0355E9D0D7608A1A0AB1 +:20FB80000A0AEDAC03A8B9AAFBC95FF01C2FE90E4FEA0F7FEF0CDFE90209804CB1EC291F0F +:20FBA00080F4B9EAFBC95FD0ED605F715F20325F60312F5E3D5F5F3B2A7E2C403A2E2D6CA5 +:20FBC000702B6E6F6B6D306A6939767568623867793778746663366472355F65737A346159 +:20FBE00077330E85838187060D085F515F20225F7E213F5E3D5F5F5D2A7E3C405B3E2D4CA8 +:20FC0000502B4E4F4B4D304A4929565548422847592758544643264452255F45535A244158 +:20FC200057231085838187020D08C6FCC4FCC4FC58FCC4FCC4FCC4FCBEFC202AEDB0189DE7 +:20FC40000205989D030538E9029D0405A92A85A5A9FC85A62047ED609E07059E08059E091A +:20FC6000052067FDA9009E05058ABC030520D0F5BD030520D8F5DA8AA85AB90205AAB90438 +:20FC800005A8200FED7AB024A9FF20AEFCB01DA5A3990605B90505C90018D01020F8E6A5FB +:20FCA000A338F90605C9B490EB20F9FCFA605A48B90205AAB90405A8682012ED7A60BD0367 +:20FCC000054CFAF518608AA8BE0205200CEDBE0505E00A9002A2007CDAFCE4FC03FD12FD35 +:20FCE00060FD66FD4CF9FCC9AAF00EC9FCF009C9FDF005A9FF4CAEFC60A904990505A9F42E +:20FD00004CAEFCC9FAF005A9D44CAEFCA904990505608003C9AA6048B90805990705B90947 +:20FD20000599080568990905B90805C9F0D008B90705D90905F00BEAB9070529CF4908F023 +:20FD40001960A906990505B907052060FDB908052060FDB909052060FD60A90899050560FB +:20FD60005A20A7FD7A60609CAD039CAE03DAA2009EAF03E8E020D0F8FA1860A200DD8FFD99 +:20FD8000F009E8E8E018D0F5A90060BD90FD6014136C967098749C11156997710475997DC3 +:20FDA00094729A7A956B9BC9F0F035C9E0F035C9E1F048C984B01DAEAD03F005207BFD807B +:20FDC00004AABD82FEAEAE03F01EAA29F0C910D0039E9F039CAD039CAE0360207BFD80E526 +:20FDE0008DAE03608DAD036020D4FDAA29F0C910D0049D9F03608AC900F0062002FE20B18E +:20FE0000EC6048A900A200BCAF03F0031D1FFEE8E009D0F3BA8902D00F8901D01568600178 +:20FE20000102020404080801BD0101291F9D010180EBBD0101203DFE9D010180E0C96190C0 +:20FE400007C97BB003492060A000D95AFEF007C8C8C028D0F560B95BFE60312132403323EA +:20FE600034243525365E3726382A392830292D5F3D2B5B7B5D7D5C7C3B3A27222C3C2E3EB5 +:20FE80002F3F008900858381828C008A888684096000001410001271310000007A736177B2 +:20FEA000320000637864653433000020766674723500006E62686779360000006D6A75371D +:20FEC0003800002C6B696F303900002E2F6C3B702D00000027005B3D000018110D5D005CC3 +:20FEE0000000000000000000080000A100A4A7000000A0AEA2A5A6A81BB08BAAA3ABACA988 +:0BFF00009D00000000879E0000000034 +:20FF81004CEEEC4CFEE94C37EC4CFCED4C0EEE4C6BEC4C4AE84C4AE84C6EEC4C7AEC4C8652 +:20FFA100EC4C01E84CC9E74CCFE74C17E84C3AE84C27E84C04E84CC1E74C32EA4C39EA4CBE +:20FFC10040EA4C67EA4C7EEA4C88EA4C92EA4CB6EA4C6DEB4C5AE84C7EE84C35EC4C35EC75 +:18FFE1004C96EC4C59EB4C86EB4C35EC4CF1EC4CF6EC4C87EC4CF6FF29 +:06FFFA004FF2ABF153F2DF +:20C0000000000000000000007E81A581BD99817E3C7EDBFFC37E3C0000EEFEFE7C381000E7 +:20C0200010387CFE7C381000003C18FFFF08180010387CFEFE1038000000183C1800000094 +:20C04000FFFFE7C3E7FFFFFF003C428181423C00FFC3BD7E7EBDC3FF0103070F1F3F7FFF66 +:20C06000FFFEFCF8F0E0C0800406070404FCF8000C0A0D0BF9F91F1F00927C44C67C92002E +:20C08000000060787E7860000000061E7E1E0600187E181818187E186666666666006600BC +:20C0A000FFB67636363636007EC1DC22221F837E0000007E7E000000187E18187E1800FFA7 +:20C0C000187E18181818180018181818187E1800000406FF06040000002060FF6020000032 +:20C0E000000000C0C0C0FF00002466FF66240000000010387CFE0000000000FE7C3810006A +:20C100000000000000000000303030303000300066660000000000006C6CFE6CFE6C6C001B +:20C12000107CD27C867C1000F096FC183E72DE0030483078CECC78000C0C18000000000089 +:20C140001060C0C0C0601000100C0606060C1000005438FE385400000018187E1818000081 +:20C1600000000000000018700000007E00000000000000000000180002060C183060C00025 +:20C180007CCEDEF6E6E67C001838781818183C007CC6060C3060FE007CC6063C06C67C003F +:20C1A0000E1E3666FE060600FEC0C0FC0606FC007CC6C0FCC6C67C00FE060C18306060000D +:20C1C0007CC6C67CC6C67C007CC6C67E06C67C000030000000300000003000000030200025 +:20C1E000001C3060301C000000007E007E0000000070180C187000007CC60C183000300069 +:20C200007C829AAAAA9E7C007CC6C6FEC6C6C600FC66667C6666FC007CC6C0C0C0C67C00F0 +:20C22000FC6666666666FC00FE6268786862FE00FE6268786860F0007CC6C6C0DEC67C0020 +:20C24000C6C6C6FEC6C6C6003C18181818183C001E0C0C0C0CCC7800C6CCD8F0D8CCC600F6 +:20C26000F06060606062FE00C6EEFED6C6C6C600C6E6F6DECEC6C6007CC6C6C6C6C67C0064 +:20C28000FC66667C6060F0007CC6C6C6C6C67C0CFC66667C6666E6007CC6C07C06C67C000C +:20C2A0007E5A181818183C00C6C6C6C6C6C67C00C6C6C6C6C66C3800C6C6C6C6D6EEC600C6 +:20C2C000C66C3838386CC6006666663C18183C00FEC60C183066FE001C18181818181C004C +:20C2E000C06030180C0602007030303030307000000010386CC6000000000000000000FF79 +:20C30000303018000000000000007C067EC67E00C0C0FCC6C6C6FC0000007CC6C0C67C0053 +:20C3200006067EC6C6C67E0000007CC6FEC07C003C6660F06060600000007EC6C67E067C0B +:20C34000C0C0FCC6C6C6C6001800381818183C00000C001C0C0CCC78C0C0C6D8F0D8C60045 +:20C360003818181818183C000000EEFED6C6C6000000FCC6C6C6C60000007CC6C6C67C0025 +:20C380000000FCC6C6FCC0C000007EC6C67E06060000DE766060600000007CC07C067C0057 +:20C3A00018187E1818181E000000C6C6C6C67E000000C6C6C66C38000000C6C6D6FEC600B7 +:20C3C0000000C66C386CC6000000C6C6C67E067C0000FE0C1860FE000E18187018180E0003 +:20C3E0001818180018181800E030301C3030E0000000709A0E0000000000183C66FF000040 +:20C400007CC6C0C0C67C18706600C6C6C6C67E000E187CC6FEC07C0018247C067EC67E0072 +:20C4200066007C067EC67E00380C7C067EC67E0018007C067EC67E0000007CC0C07C18706E +:20C4400018247CC6FEC07C0066007CC6FEC07C0070187CC6FEC07C006600381818183C001C +:20C460001824381818183C00380C381818183C0066007CC6FEC6C60018007CC6FEC6C600AE +:20C480000E18FE607860FE0000007C1A7ED87E007ED8D8DEF8D8DE0018247CC6C6C67C0098 +:20C4A00066007CC6C6C67C00380C7CC6C6C67C001824C6C6C6C67E00380CC6C6C6C67E0092 +:20C4C0006600C6C6C67E067C667CC6C6C6C67C00C600C6C6C6C67C00187CC6C0C67C180060 +:20C4E0001E3230783070FE00663C187E183C1800FCC6FCC0CCDECC0E001C3230FC30F00066 +:20C500000E187C067EC67E001A30381818183C000E187CC6C6C67C000E18C6C6C6C67E007F +:20C520006698FCC6C6C6C6006698E6F6DECEC6007C067EC67E00FE007CC6C6C67C00FE0013 +:20C540001800183060C67C000000FEC0C0C0C0000000FE0606060600C0C0C0DE060C1E0077 +:20C56000C0C0C0CC1C3E0C00300030303030300000366CD86C36000000D86C366CD800004F +:20C58000AAAAAAAAAAAAAAAAAA55AA55AA55AA5544224422442244221818181818181818F7 +:20C5A000181818F818181818181818F818F81818363636F636363636000000FE3636363615 +:20C5C000000000F818F81818363636F606F636363636363636363636000000FE06F636360D +:20C5E000363636F606FE0000363636FE00000000181818F818F80000000000F81818181857 +:20C600001818181F00000000181818FF00000000000000FF181818181818181F1818181846 +:20C62000000000FF00000000181818FF181818181818181F181F18183636363736363636D5 +:20C6400036363637303F00000000003F30373636363636F700FF0000000000FF00F7363686 +:20C660003636363730373636000000FF00FF0000363636F700F73636181818FF00FF0000CE +:20C68000363636FF00000000000000FF00FF1818000000FF363636363636363F0000000013 +:20C6A0001818181F181F00000000001F181F18180000003F36363636363636FF36363636C6 +:20C6C000181818FF18FF1818181818F8000000000000001F18181818FFFFFFFFFFFFFFFF15 +:20C6E00000000000FFFFFFFFF0F0F0F0F0F0F0F00F0F0F0F0F0F0F0FFFFFFFFF000000004A +:20C7000000007798987700001C3666FCC6C6FCC0FE626060606060000000FF666666660028 +:20C72000FE6230183062FE0000003F66C6CC780000003333333E30F00000FF1818181800BC +:20C740003C183C66663C183C007CC6FEC67C0000007EC3C3C366E7001E193C66C6CC780074 +:20C76000000066999966000000037CCEE67CC000003EC0FEC03E0000007EC3C3C3C30000C8 +:20C7800000FE00FE00FE000018187E18187E000070180C187000FE001C3060301C00FE0033 +:20C7A000000E1B18181818181818181818D870000018007E001800000076DC0076DC0000C6 +:20C7C0003C663C000000000000183C180000000000000000180000000F0C0C0CEC6C380034 +:20C7E000D8ECCCCC00000000F030C0F0000000000000003C3C3C3C0000000000000000001D +:00000001FF diff --git a/Main/roms/kernel_F256jr.lst b/Main/roms/kernel_F256jr.lst new file mode 100644 index 0000000..d0317c5 --- /dev/null +++ b/Main/roms/kernel_F256jr.lst @@ -0,0 +1,5950 @@ + +; 64tass Turbo Assembler Macro V1.54.1900 listing file +; 64tass.exe -I . -C -Wall -Werror -Wno-shadow -x --verbose-list -b -L bin/C256jr.lst -o bin/C256jr.bin core/kernel.asm core/iec.asm core/io.asm core/dev.asm core/dev_screen.asm core/dev_keyboard.asm core/rtc.asm core/sys.asm core/keyboard.asm core/video.asm core/device.asm core/token.asm core/vectors.asm core/cli.asm core/cli_list.asm core/cli_load.asm platform/jr/jr.asm platform/jr/iec.asm platform/jr/irq.asm platform/jr/ps2.asm platform/jr/console.asm platform/jr/c64kbd.asm platform/jr/FPGA/TinyVicky_Def.asm platform/jr/FPGA/interrupt_def.asm hardware/hardware.asm hardware/i8042.asm hardware/ps2.asm hardware/ps2_kbd2.asm hardware/keys.asm +; Wed Oct 19 20:40:21 2022 + +;Offset ;Hex ;Monitor ;Source + +;****** Processing input file: core/kernel.asm + + ; OpenKERNAL - a clean-room implementation of the C64's KERNAL ABI. + ; Copyright 2022 Jessie Oberreuter . + ; SPDX-License-Identifier: GPL-3.0-only + + ; Memory layout and general support for TinyCore device drivers. + + .cpu "w65c02" + + ;reserved = $0000 ; $00 - $02 + ;basic = $0002 ; $02 - $90 + * = $0090 ; $90 - $fb kernel + * = $00a3 ; $90 - $fb kernel +.00a3 DP .dsection dp + .cerror * >= $00fb, "Out of dp space." + + * = $0100 ; Stack +>0100 Stack .fill $100 + + * = $0200 ; BASIC, some KERNAL +>0200 Tokens .fill $90 ; BASIC +.0290 p2end +.0290 tokens_start + .cerror * > $02ff, "Out of kmem space." + + * = $0300 +>0300 .fill $34 ; Shared vectors +.0334 p3end +.0334 KBUF .dsection kbuf ; kernal +.0344 KMEM .dsection kmem ; KERNAL + .cerror * > $03ff, "Out of kbuf space." + + * = $0400 ; Device tables (from the TinyCore kernel) + .dsection kpages + + +=$800 free_mem = $800 ; Traditional start. + + + + ; $e000 - $e500 contains a simple command line shell which may be + ; used to load applications in the absence of either CBM BASIC or + ; a more general ROM. If CBM BASIC is bundled, it will overwrite + ; this section of the kernel. + + * = $e000 + .dsection shell + .cerror * > $e4ff, "Out of shell space." + + ; Start of the kernel proper, pushed back to accomodate the use of + ; CBM BASIC. + * = $e500 + .dsection tables + .dsection kernel + .cerror * > $fff0, "Out of kernel space." + + * = $ff81 + kernel .namespace + .dstruct vectors +.ff81 4c ee ec jmp $ecee SCINIT jmp scinit +.ff84 4c fe e9 jmp $e9fe IOINIT jmp io.ioinit +.ff87 4c 37 ec jmp $ec37 RAMTAS jmp ramtas +.ff8a 4c fc ed jmp $edfc RESTOR jmp restor +.ff8d 4c 0e ee jmp $ee0e VECTOR jmp vector +.ff90 4c 6b ec jmp $ec6b SETMSG jmp setmsg +.ff93 4c 4a e8 jmp $e84a LSTNSA jmp iec.lstnsa +.ff96 4c 4a e8 jmp $e84a TALKSA jmp iec.talksa +.ff99 4c 6e ec jmp $ec6e MEMBOT jmp membot +.ff9c 4c 7a ec jmp $ec7a MEMTOP jmp memtop +.ff9f 4c 86 ec jmp $ec86 SCNKEY jmp scnkey +.ffa2 4c 01 e8 jmp $e801 SETTMO jmp iec.settmo +.ffa5 4c c9 e7 jmp $e7c9 IECIN jmp iec.iecin +.ffa8 4c cf e7 jmp $e7cf IECOUT jmp iec.iecout +.ffab 4c 17 e8 jmp $e817 UNTALK jmp iec.untalk +.ffae 4c 3a e8 jmp $e83a UNLSTN jmp iec.unlstn +.ffb1 4c 27 e8 jmp $e827 LISTEN jmp iec.listen +.ffb4 4c 04 e8 jmp $e804 TALK jmp iec.talk +.ffb7 4c c1 e7 jmp $e7c1 READST jmp iec.readst +.ffba 4c 32 ea jmp $ea32 SETLFS jmp io.setlfs +.ffbd 4c 39 ea jmp $ea39 SETNAM jmp io.setnam +.ffc0 4c 40 ea jmp $ea40 OPEN jmp io.open +.ffc3 4c 67 ea jmp $ea67 CLOSE jmp io.close +.ffc6 4c 7e ea jmp $ea7e CHKIN jmp io.chkin +.ffc9 4c 88 ea jmp $ea88 CHKOUT jmp io.chkout +.ffcc 4c 92 ea jmp $ea92 CLRCHN jmp io.clrchn +.ffcf 4c b6 ea jmp $eab6 CHRIN jmp io.chrin +.ffd2 4c 6d eb jmp $eb6d CHROUT jmp io.chrout +.ffd5 4c 5a e8 jmp $e85a LOAD jmp iec.load +.ffd8 4c 7e e8 jmp $e87e SAVE jmp iec.save +.ffdb 4c 35 ec jmp $ec35 SETTIM jmp settim +.ffde 4c 35 ec jmp $ec35 RDTIM jmp rdtim +.ffe1 4c 96 ec jmp $ec96 STOP jmp keyboard.stop +.ffe4 4c 59 eb jmp $eb59 GETIN jmp io.getin +.ffe7 4c 86 eb jmp $eb86 CLALL jmp io.clall +.ffea 4c 35 ec jmp $ec35 UDTIM jmp udtim +.ffed 4c f1 ec jmp $ecf1 SCREEN jmp screen +.fff0 4c f6 ec jmp $ecf6 PLOT jmp plot +.fff3 4c 87 ec jmp $ec87 IOBASE jmp iobase + .ends + .endn + + .section kpages +.0400 frame +>0400 Devices .fill 256 +>0500 DevState .fill 256 + .send + + .namespace kernel + + .section dp +>00a3 ticks .word ? +>00a5 src .word ? ; src ptr for copy operations. +>00a7 dest .word ? ; dest ptr for copy operations. +>00a9 size .word ? ; size of data at dest. +>00ab tos_l .byte ? ; For BCD conversions +>00ac tos_h .byte ? +>00ad fname .word ? ; file name pointer +>00af fname_len .byte ? ; file name length +>00b0 cur_logical .byte ? ; current logical device +>00b1 cur_device .byte ? ; current assoc dev # +>00b2 cur_addr .byte ? ; current associated secondary addr + .send + + + .section dp +>00b3 mem_start .word ? +>00b5 mem_end .word ? +>00b7 msg_switch .byte ? +>00b8 current_dev .byte ? + .send + + +=1 TOO_MANY_FILES = 1 +=2 FILE_OPEN = 2 +=3 FILE_NOT_OPEN = 3 +=4 FILE_NOT_FOUND = 4 +=5 DEVICE_NOT_PRESENT = 5 +=6 NOT_INPUT_FILE = 6 +=7 NOT_OUTPUT_FILE = 7 +=8 MISSING_FILE_NAME = 8 +=9 ILLEGAL_DEVICE_NUMBER = 9 + + .section kernel + +.e600 copyright +>e600 4f 70 65 6e 4b 45 52 4e .text "OpenKERNAL - a clean-room implementation of the C64 KERNAL ABI",13 +>e608 41 4c 20 2d 20 61 20 63 6c 65 61 6e 2d 72 6f 6f +>e618 6d 20 69 6d 70 6c 65 6d 65 6e 74 61 74 69 6f 6e +>e628 20 6f 66 20 74 68 65 20 43 36 34 20 4b 45 52 4e +>e638 41 4c 20 41 42 49 0d +>e63f 43 6f 70 79 72 69 67 68 .text "Copyright 2022 Jessie Oberreuter .",13 +>e647 74 20 32 30 32 32 20 4a 65 73 73 69 65 20 4f 62 +>e657 65 72 72 65 75 74 65 72 20 3c 47 61 64 67 65 74 +>e667 40 48 61 63 6b 77 72 65 6e 63 68 4c 61 62 73 2e +>e677 63 6f 6d 3e 2e 0d +>e67d 52 65 6c 65 61 73 65 64 .text "Released under the GPL3 license with the kernel exception:",13 +>e685 20 75 6e 64 65 72 20 74 68 65 20 47 50 4c 33 20 +>e695 6c 69 63 65 6e 73 65 20 77 69 74 68 20 74 68 65 +>e6a5 20 6b 65 72 6e 65 6c 20 65 78 63 65 70 74 69 6f +>e6b5 6e 3a 0d +>e6b8 61 70 70 6c 69 63 61 74 .text "applications which simply use the ABI are not 'derived works'.", 13 +>e6c0 69 6f 6e 73 20 77 68 69 63 68 20 73 69 6d 70 6c +>e6d0 79 20 75 73 65 20 74 68 65 20 41 42 49 20 61 72 +>e6e0 65 20 6e 6f 74 20 27 64 65 72 69 76 65 64 20 77 +>e6f0 6f 72 6b 73 27 2e 0d +>e6f7 00 .byte 0 + + thread .namespace ; For devices borrowed from the TinyCore kernel. +.e6f8 cb wai yield wai +.e6f9 60 rts rts + .endn + +.e6fa init + ; Initialize device driver services. +.e6fa 20 a6 ed jsr $eda6 jsr token.init +.e6fd 20 18 ed jsr $ed18 jsr device.init +.e700 20 8c ec jsr $ec8c jsr keyboard.init +.e703 60 rts rts + +.e704 tick +.e704 e6 a3 inc $a3 inc kernel.ticks +.e706 d0 02 bne $e70a bne _end +.e708 e6 a4 inc $a4 inc kernel.ticks+1 +.e70a 60 rts _end rts + + +.e70b banner +.e70b a9 00 lda #$00 lda #copyright +.e711 85 a6 sta $a6 sta src+1 +.e713 4c 16 e7 jmp $e716 jmp puts + +.e716 puts +.e716 a0 00 ldy #$00 ldy #0 +.e718 b1 a5 lda ($a5),y _loop lda (src),y +.e71a f0 0a beq $e726 beq _done +.e71c 20 d2 ff jsr $ffd2 jsr CHROUT +.e71f c8 iny iny +.e720 d0 f6 bne $e718 bne _loop +.e722 e6 a6 inc $a6 inc src+1 +.e724 80 f2 bra $e718 bra _loop +.e726 _done +.e726 18 clc clc +.e727 60 rts rts + +.e728 error +.e728 48 pha pha +.e729 a9 4a lda #$4a lda #<_msg +.e72b 85 a5 sta $a5 sta src +.e72d a9 e7 lda #$e7 lda #>_msg +.e72f 85 a6 sta $a6 sta src+1 +.e731 a0 00 ldy #$00 ldy #0 +.e733 b1 a5 lda ($a5),y _loop lda (src),y +.e735 f0 06 beq $e73d beq _done +.e737 20 b9 f9 jsr $f9b9 jsr platform.console.putc +.e73a c8 iny iny +.e73b 80 f6 bra $e733 bra _loop +.e73d _done +.e73d 68 pla pla +.e73e 18 clc clc +.e73f 69 30 adc #$30 adc #'0' +.e741 20 b9 f9 jsr $f9b9 jsr platform.console.putc +.e744 a9 0d lda #$0d lda #13 +.e746 20 b9 f9 jsr $f9b9 jsr platform.console.putc +.e749 60 rts rts +>e74a 45 72 72 6f 72 20 00 _msg .null "Error " + +.e751 a0 ff ldy #$ff strcmp ldy #$ff +.e753 c8 iny _loop iny +.e754 b1 a5 lda ($a5),y lda (src),y +.e756 f0 04 beq $e75c beq _out +.e758 51 a7 eor ($a7),y eor (dest),y +.e75a f0 f7 beq $e753 beq _loop +.e75c 60 rts _out rts + + + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ; CBM stuff below ... move to another file. + +=$a000 basic = $a000 + +.e75d start +.e75d 64 01 stz $01 stz $1 ; Default to the sys map. + +.e75f 20 37 ec jsr $ec37 jsr ramtas +.e762 20 fc ed jsr $edfc jsr restor +.e765 20 81 ff jsr $ff81 jsr SCINIT +.e768 20 84 ff jsr $ff84 jsr IOINIT +.e76b 4c 6e e7 jmp $e76e jmp chain + +.e76e chain +.e76e a2 00 ldx #$00 ldx #0 +.e770 _loop + ; Point src and dest at the expected signature and offset +.e770 bd 94 e7 lda $e794,x lda _table,x +.e773 85 a5 sta $a5 sta src+0 +.e775 e8 inx inx +.e776 bd 94 e7 lda $e794,x lda _table,x +.e779 85 a6 sta $a6 sta src+1 +.e77b e8 inx inx +.e77c bd 94 e7 lda $e794,x lda _table,x +.e77f 85 a7 sta $a7 sta dest+0 +.e781 e8 inx inx +.e782 bd 94 e7 lda $e794,x lda _table,x +.e785 85 a8 sta $a8 sta dest+1 +.e787 e8 inx inx + + ; Chain on signature match. +.e788 20 51 e7 jsr $e751 jsr strcmp +.e78b d0 03 bne $e790 bne _next +.e78d 7c 94 e7 jmp ($e794,x) jmp (_table,x) +.e790 e8 inx _next inx +.e791 e8 inx inx +.e792 80 dc bra $e770 bra _loop +.e794 _table +>e794 a6 e7 04 a0 af e7 .word cbm_bytes, $a004, cbm_start ; Check for CBM BASIC +>e79a b2 e7 04 80 ba e7 .word bas02_bytes, $8004, bas02_start ; Check for BASIC02 +>e7a0 bd e7 00 e0 be e7 .word cli_bytes, $e000, cli_start ; Always last + +>e7a6 43 42 4d 42 41 53 49 43 cbm_bytes .null "CBMBASIC" +>e7ae 00 +.e7af 6c 00 a0 jmp ($a000) cbm_start jmp (basic) + +>e7b2 42 41 53 49 43 30 32 00 bas02_bytes .null "BASIC02" +.e7ba 4c 00 80 jmp $8000 bas02_start jmp $8000 + +>e7bd 00 cli_bytes .null "" ; Fall-through match. +.e7be 4c ab e1 jmp $e1ab cli_start jmp shell.start + + +.0000 vectors .struct +.0000 4c ee ec jmp $ecee SCINIT jmp scinit +.0003 4c fe e9 jmp $e9fe IOINIT jmp io.ioinit +.0006 4c 37 ec jmp $ec37 RAMTAS jmp ramtas +.0009 4c fc ed jmp $edfc RESTOR jmp restor +.000c 4c 0e ee jmp $ee0e VECTOR jmp vector +.000f 4c 6b ec jmp $ec6b SETMSG jmp setmsg +.0012 4c 4a e8 jmp $e84a LSTNSA jmp iec.lstnsa +.0015 4c 4a e8 jmp $e84a TALKSA jmp iec.talksa +.0018 4c 6e ec jmp $ec6e MEMBOT jmp membot +.001b 4c 7a ec jmp $ec7a MEMTOP jmp memtop +.001e 4c 86 ec jmp $ec86 SCNKEY jmp scnkey +.0021 4c 01 e8 jmp $e801 SETTMO jmp iec.settmo +.0024 4c c9 e7 jmp $e7c9 IECIN jmp iec.iecin +.0027 4c cf e7 jmp $e7cf IECOUT jmp iec.iecout +.002a 4c 17 e8 jmp $e817 UNTALK jmp iec.untalk +.002d 4c 3a e8 jmp $e83a UNLSTN jmp iec.unlstn +.0030 4c 27 e8 jmp $e827 LISTEN jmp iec.listen +.0033 4c 04 e8 jmp $e804 TALK jmp iec.talk +.0036 4c c1 e7 jmp $e7c1 READST jmp iec.readst +.0039 4c 32 ea jmp $ea32 SETLFS jmp io.setlfs +.003c 4c 39 ea jmp $ea39 SETNAM jmp io.setnam +.003f 4c 40 ea jmp $ea40 OPEN jmp io.open +.0042 4c 67 ea jmp $ea67 CLOSE jmp io.close +.0045 4c 7e ea jmp $ea7e CHKIN jmp io.chkin +.0048 4c 88 ea jmp $ea88 CHKOUT jmp io.chkout +.004b 4c 92 ea jmp $ea92 CLRCHN jmp io.clrchn +.004e 4c b6 ea jmp $eab6 CHRIN jmp io.chrin +.0051 4c 6d eb jmp $eb6d CHROUT jmp io.chrout +.0054 4c 5a e8 jmp $e85a LOAD jmp iec.load +.0057 4c 7e e8 jmp $e87e SAVE jmp iec.save +.005a 4c 35 ec jmp $ec35 SETTIM jmp settim +.005d 4c 35 ec jmp $ec35 RDTIM jmp rdtim +.0060 4c 96 ec jmp $ec96 STOP jmp keyboard.stop +.0063 4c 59 eb jmp $eb59 GETIN jmp io.getin +.0066 4c 86 eb jmp $eb86 CLALL jmp io.clall +.0069 4c 35 ec jmp $ec35 UDTIM jmp udtim +.006c 4c f1 ec jmp $ecf1 SCREEN jmp screen +.006f 4c f6 ec jmp $ecf6 PLOT jmp plot +.0072 4c 87 ec jmp $ec87 IOBASE jmp iobase + .ends + + + .send + .endn + + +;****** Processing input file: core/iec.asm + + ; OpenKERNAL - a clean-room implementation of the C64's KERNAL ABI. + ; Copyright 2022 Jessie Oberreuter . + ; SPDX-License-Identifier: GPL-3.0-only + + .cpu "w65c02" + + .namespace kernel + iec .namespace + + .section dp +>00b9 queue .byte ? ; queue to detect when to signal end-of-data +>00ba queued .byte ? ; negative if a byte is in the queue +>00bb status .byte ? ; IEC status + .send + + .section kernel + +=1 TIMEOUT_WRITE = 1 +=2 TIMEOUT_READ = 2 +=16 MISMATCH = 16 +=64 EOI = 64 +=128 NO_DEVICE = 128 + +.e7c1 readst +.e7c1 a5 bb lda $bb lda status +.e7c3 60 rts rts + +.e7c4 error + + ; Internal function. + ; Updates io.status with the bits set in A. + ; Does not change the state of the carry. + +.e7c4 05 bb ora $bb ora status +.e7c6 85 bb sta $bb sta status +.e7c8 60 rts rts + +.e7c9 iecin +.e7c9 20 8d f3 jsr $f38d jsr platform.iec.read_byte +.e7cc b0 f6 bcs $e7c4 bcs error +.e7ce 60 rts rts + +.e7cf iecout +.e7cf queue_data + + ; Delays writes of data bytes to the IEC bus by one character. + ; This enables the stack to automatically determine when to + ; signal that this is the last data byte in its sequence. + ; On error, sets carry and returns the READST value in A. + +.e7cf 24 ba bit $ba bit queued +.e7d1 30 05 bmi $e7d8 bmi _swap +.e7d3 85 b9 sta $b9 sta queue +.e7d5 c6 ba dec $ba dec queued +.e7d7 60 rts rts +.e7d8 _swap +.e7d8 48 pha pha +.e7d9 a5 b9 lda $b9 lda queue +.e7db 20 ca f3 jsr $f3ca jsr platform.iec.write_byte +.e7de 90 03 bcc $e7e3 bcc _okay +.e7e0 20 c4 e7 jsr $e7c4 jsr error +.e7e3 68 pla _okay pla +.e7e4 85 b9 sta $b9 sta queue +.e7e6 60 rts _out rts + + +.e7e7 flush_queue + + ; Internal function + ; If there is a byte remaining in the queue, send it + ; using the IEC "last byte" protocol. + ; On error, sets carry and returns the READST value in A. + +.e7e7 24 ba bit $ba bit queued +.e7e9 10 09 bpl $e7f4 bpl _done +.e7eb a5 b9 lda $b9 lda queue +.e7ed 20 d4 f3 jsr $f3d4 jsr platform.iec.write_last_byte +.e7f0 b0 d2 bcs $e7c4 bcs error +.e7f2 64 ba stz $ba stz queued +.e7f4 60 rts _done rts + + +.e7f5 reset + + ; Internal function. + ; Clears the write queue and the READST value. + +.e7f5 64 bb stz $bb stz status +.e7f7 64 ba stz $ba stz queued +.e7f9 60 rts rts + +.e7fa check_dev + + ; Internal function. + ; Ensures that the device number in A is valid for the IEC + ; bus. Sets the carry and returns A=#NO_DEVICE on error. + +.e7fa c9 10 cmp #$10 cmp #16 +.e7fc 90 02 bcc $e800 bcc _out +.e7fe a9 80 lda #$80 lda #NO_DEVICE +.e800 60 rts _out rts + +.e801 settmo + ; Implemented by platform; repeated here for consistency. + +.e801 4c 8a f3 jmp $f38a jmp platform.iec.settmo + +.e804 talk + + ; IN: A = device (8..15) + ; NOTE: The iec routines don't appear to return any status; + ; instead, users are expected to call READST after + ; each invocation. In this particular implementation, + ; carry will be set, and A will contain the value to + ; be returned by READST. + +.e804 20 f5 e7 jsr $e7f5 jsr reset +.e807 20 fa e7 jsr $e7fa jsr check_dev +.e80a b0 08 bcs $e814 bcs _error +.e80c 09 40 ora #$40 ora #$40 +.e80e 20 de f3 jsr $f3de jsr platform.iec.send_atn_byte +.e811 b0 01 bcs $e814 bcs _error +.e813 60 rts rts +.e814 4c c4 e7 jmp $e7c4 _error jmp error + + +.e817 untalk + + ; NOTE: The iec routines don't appear to return any status; + ; instead, users are expected to call READST after + ; each invocation. In this particular implementation, + ; carry will be set, and A will contain the value to + ; be returned by READST. + +.e817 20 e7 e7 jsr $e7e7 jsr flush_queue +.e81a b0 08 bcs $e824 bcs _error +.e81c a9 5f lda #$5f lda #$5f +.e81e 20 f1 f3 jsr $f3f1 jsr platform.iec.send_atn_last_byte +.e821 b0 01 bcs $e824 bcs _error +.e823 60 rts rts +.e824 4c c4 e7 jmp $e7c4 _error jmp error + +.e827 listen + + ; IN: A = device (8..15) + ; NOTE: The iec routines don't appear to return any status; + ; instead, users are expected to call READST after + ; each invocation. In this particular implementation, + ; carry will be set, and A will contain the value to + ; be returned by READST. + +.e827 20 f5 e7 jsr $e7f5 jsr reset +.e82a 20 fa e7 jsr $e7fa jsr check_dev +.e82d b0 08 bcs $e837 bcs _error +.e82f 09 20 ora #$20 ora #$20 +.e831 20 de f3 jsr $f3de jsr platform.iec.send_atn_byte +.e834 b0 01 bcs $e837 bcs _error +.e836 60 rts rts +.e837 4c c4 e7 jmp $e7c4 _error jmp error + + +.e83a unlstn + + ; NOTE: The iec routines don't appear to return any status; + ; instead, users are expected to call READST after + ; each invocation. In this particular implementation, + ; carry will be set, and A will contain the value to + ; be returned by READST. + +.e83a 20 e7 e7 jsr $e7e7 jsr flush_queue +.e83d b0 08 bcs $e847 bcs _error +.e83f a9 3f lda #$3f lda #$3f +.e841 20 f1 f3 jsr $f3f1 jsr platform.iec.send_atn_last_byte +.e844 b0 01 bcs $e847 bcs _error +.e846 60 rts rts +.e847 4c c4 e7 jmp $e7c4 _error jmp error + +.e84a talksa +.e84a lstnsa + + ; IN: A = device (8..15) + ; NOTE: The iec routines don't appear to return any status; + ; instead, users are expected to call READST after + ; each invocation. In this particular implementation, + ; carry will be set, and A will contain the value to + ; be returned by READST. + ; + ; These two routines are nominally separate to hint the kernel + ; about what the bus is expected to do. On the C256 Jr., the + ; state machine in the FPGA automatically handles both cases. + +.e84a 20 fa e7 jsr $e7fa jsr check_dev +.e84d b0 08 bcs $e857 bcs _error +.e84f 09 60 ora #$60 ora #$60 +.e851 20 de f3 jsr $f3de jsr platform.iec.send_atn_byte +.e854 b0 01 bcs $e857 bcs _error +.e856 60 rts rts +.e857 4c c4 e7 jmp $e7c4 _error jmp error + + + +.e85a load + + ; IN: Device and sub set using SETLFS + ; File name set using SETNAM + ; A= 0->read, 1..255->verify + ; X/Y = dest address (if secondary != 0) + ; + ; OUT: X/Y = end address, or carry set and A = error. + ; + ; NOTE: On error, A is a KERNAL error, NOT a READST vlaue! + + ; initialize dest; may be overriden later +.e85a 86 a7 stx $a7 stx dest+0 +.e85c 84 a8 sty $a8 sty dest+1 + + ; X = read/verify +.e85e aa tax tax + + ; Y = flag to use address in file over dest address above. +.e85f a4 b2 ldy $b2 ldy cur_addr + + ; Open the file for read. + ; NOTE: returns a KERNAL error; must check READST as well! +.e861 20 80 e8 jsr $e880 jsr open_file_for_read +.e864 b0 11 bcs $e877 bcs _out +.e866 20 b7 ff jsr $ffb7 jsr READST +.e869 09 00 ora #$00 ora #0 +.e86b d0 0b bne $e878 bne _error + + ; Read the file, sets X/Y to last address. +.e86d 20 eb e8 jsr $e8eb jsr read_verify_pgm_data +.e870 b0 06 bcs $e878 bcs _error + +.e872 20 d2 e8 jsr $e8d2 jsr close_file +.e875 b0 01 bcs $e878 bcs _error + +.e877 60 rts _out rts +.e878 _error +.e878 20 c4 e7 jsr $e7c4 jsr error ; Update status for READST. +.e87b 18 clc clc ; I/O errors aren't KERANL errors... +.e87c 80 f9 bra $e877 bra _out + + +.e87e save +.e87e 38 sec sec +.e87f 60 rts rts + +.e880 open_file_for_read + + ; Internal function. + ; + ; IN: Device and sub set using SETLFS + ; File name set using SETNAM + ; + ; OUT: Carry set and A = a KERNEL error + ; (MISSING_FILE_NAME) on error. + ; + ; NOTE: On IEC error, Sets READST and CLEARS the carry. + +.e880 a5 af lda $af lda fname_len +.e882 d0 04 bne $e888 bne _open +.e884 a9 08 lda #$08 lda #MISSING_FILE_NAME ; Only KERNAL error returned. +.e886 38 sec sec +.e887 60 rts rts + +.e888 _open +.e888 a5 b1 lda $b1 lda cur_device +.e88a 20 b1 ff jsr $ffb1 jsr LISTEN +.e88d b0 20 bcs $e8af bcs _error + +.e88f a9 f0 lda #$f0 lda #$f0 ; Open channel 0 +.e891 20 de f3 jsr $f3de jsr platform.iec.send_atn_byte +.e894 b0 19 bcs $e8af bcs _error + +.e896 20 b1 e8 jsr $e8b1 jsr send_fname +.e899 b0 14 bcs $e8af bcs _error + +.e89b 20 ae ff jsr $ffae jsr UNLSTN +.e89e b0 0f bcs $e8af bcs _error + +.e8a0 a5 b1 lda $b1 lda cur_device +.e8a2 20 b4 ff jsr $ffb4 jsr TALK +.e8a5 b0 08 bcs $e8af bcs _error + +.e8a7 a9 00 lda #$00 lda #0 ; Channel 0; Channel 1 magic is internal. +.e8a9 20 96 ff jsr $ff96 jsr TALKSA ; Reopen channel; tells drive to send. +.e8ac b0 01 bcs $e8af bcs _error + +.e8ae 60 rts rts + +.e8af _error + ; Not a KERNEL error; must call READST for more information. +.e8af 18 clc clc +.e8b0 60 rts rts + + +.e8b1 send_fname + + ; Internal function + ; Writes the filename (from SETFN) via the IECOUT. + ; Returns the IEC error status. + +.e8b1 5a phy phy +.e8b2 a0 00 ldy #$00 ldy #0 +.e8b4 _loop +.e8b4 b1 ad lda ($ad),y lda (fname),y +.e8b6 20 c6 e8 jsr $e8c6 jsr to_upper +.e8b9 20 a8 ff jsr $ffa8 jsr IECOUT +.e8bc b0 06 bcs $e8c4 bcs _out +.e8be c8 iny iny +.e8bf c4 af cpy $af cpy fname_len +.e8c1 90 f1 bcc $e8b4 bcc _loop +.e8c3 18 clc clc +.e8c4 _out +.e8c4 7a ply ply +.e8c5 60 rts rts + +.e8c6 to_upper +.e8c6 c9 61 cmp #$61 cmp #'a' +.e8c8 90 06 bcc $e8d0 bcc _okay +.e8ca c9 7b cmp #$7b cmp #'z'+1 +.e8cc b0 02 bcs $e8d0 bcs _okay +.e8ce 49 20 eor #$20 eor #$20 +.e8d0 18 clc _okay clc +.e8d1 60 rts rts + +.e8d2 close_file + + ; Internal function + ; Closes the current reading or writing file. + ; Returns the IEC error status. + +.e8d2 20 ab ff jsr $ffab jsr UNTALK +.e8d5 b0 13 bcs $e8ea bcs _out + +.e8d7 a5 b1 lda $b1 lda cur_device +.e8d9 20 b1 ff jsr $ffb1 jsr LISTEN +.e8dc b0 0c bcs $e8ea bcs _out + +.e8de a9 e0 lda #$e0 lda #$e0 ; Close channel 0 +.e8e0 20 de f3 jsr $f3de jsr platform.iec.send_atn_byte +.e8e3 b0 05 bcs $e8ea bcs _out + +.e8e5 20 ae ff jsr $ffae jsr UNLSTN +.e8e8 b0 00 bcs $e8ea bcs _out + +.e8ea 60 rts _out rts + + +.e8eb read_verify_pgm_data + + ; Internal funciton. + ; Implements READ/VERIFY for PGM files. + ; + ; IN: Y=0 (load to dest) or Y=1 (load to embedded address) + ; X=0 (read) or 1..255 (verify) + ; + ; Out: X:Y = last address read/verified + ; On error, Carry set, and A = IEC error (READST value) + + + ; X = 0/2 read/verify +.e8eb aa tax tax +.e8ec f0 02 beq $e8f0 beq _emode ; read +.e8ee a2 02 ldx #$02 ldx #2 ; verify +.e8f0 ea nop _emode nop + + ; Read the would-be load-address into src +.e8f1 20 a5 ff jsr $ffa5 jsr IECIN +.e8f4 b0 21 bcs $e917 bcs _notfound +.e8f6 85 a5 sta $a5 sta src+0 +.e8f8 20 a5 ff jsr $ffa5 jsr IECIN +.e8fb b0 1a bcs $e917 bcs _notfound +.e8fd 85 a6 sta $a6 sta src+1 + + ; Update dest ptr if the sub-channel (Y) is 1 +.e8ff 98 tya tya +.e900 f0 08 beq $e90a beq _edest +.e902 a5 a5 lda $a5 lda src+0 +.e904 85 a7 sta $a7 sta dest+0 +.e906 a5 a6 lda $a6 lda src+1 +.e908 85 a8 sta $a8 sta dest+1 +.e90a ea nop _edest nop + +.e90b _loop +.e90b 20 a5 ff jsr $ffa5 jsr IECIN +.e90e 90 0e bcc $e91e bcc _found +.e910 c9 40 cmp #$40 cmp #EOI +.e912 f0 15 beq $e929 beq _done +.e914 4c c4 e7 jmp $e7c4 _error jmp error ; Forward the IEC error status. +.e917 20 c4 e7 jsr $e7c4 _notfound jsr error ; Forward the IEC error status. +.e91a a9 04 lda #$04 lda #FILE_NOT_FOUND +.e91c 38 sec sec +.e91d 60 rts rts +.e91e 7c 2f e9 jmp ($e92f,x) _found jmp (_op,x) +.e921 _cont +.e921 e6 a7 inc $a7 inc dest +.e923 d0 02 bne $e927 bne _next +.e925 e6 a8 inc $a8 inc dest+1 +.e927 _next +.e927 90 e2 bcc $e90b bcc _loop +.e929 18 clc _done clc +.e92a _out +.e92a a6 a7 ldx $a7 ldx dest+0 +.e92c a4 a8 ldy $a8 ldy dest+1 +.e92e 60 rts rts +.e92f _op +>e92f 33 e9 .word _load +>e931 37 e9 .word _verify +.e933 _load +.e933 92 a7 sta ($a7) sta (dest) +.e935 80 ea bra $e921 bra _cont +.e937 _verify +.e937 d2 a7 cmp ($a7) cmp (dest) +.e939 f0 e6 beq $e921 beq _cont +.e93b a9 10 lda #$10 lda #MISMATCH +.e93d 38 sec sec +.e93e 20 14 e9 jsr $e914 jsr _error +.e941 80 e7 bra $e92a bra _out ; Mismatch still returns X/Y. + + .send + .endn + .endn + + +;****** Processing input file: core/io.asm + + ; OpenKERNAL - a clean-room implementation of the C64's KERNAL ABI. + ; Copyright 2022 Jessie Oberreuter . + ; SPDX-License-Identifier: GPL-3.0-only + + .cpu "w65c02" + + .namespace kernel + .namespace io + + .section dp + +>00bc cur_in .byte ? ; current input device +>00bd cur_out .byte ? ; current output device +>00be io_last .byte ? ; device # of most recent read/write operation +>00bf io_status .byte ? ; status from most recent read/write operation + + ; These could be moved to the file object +>00c0 scraping .byte ? ; screen scraping bool. +>00c1 scrape_x .byte ? ; screen scrape x value. +>00c2 quoted .byte ? ; screen scrape inside quotes. + + .send + +=10 MAX_FILES = 10 + + .section kmem +>0344 files .fill MAX_FILES * 8 + .send + + file .namespace + .virtual files +>0344 state .byte ? ; OPEN/CLOSED state +>0345 device .byte ? +>0346 secondary .byte ? + .endv + .endn + + .section kernel + +.e943 spin +.e943 a9 02 lda #$02 lda #2 +.e945 85 01 sta $01 sta $1 +.e947 _loop +.e947 ad 00 c0 lda $c000 lda $c000 +.e94a 1a inc a inc a +.e94b 8d 00 c0 sta $c000 sta $c000 +.e94e 80 f7 bra $e947 bra _loop + + + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +.e950 find: + + ; IN: A = logical file # + ; SUCCESS: + ; Carry clear + ; X->device entry + ; Y->file entry + ; FAIL: + ; Carry set + ; A = FILE_NOT_OPEN or TOO_MANY_FILES + +.e950 20 6c e9 jsr $e96c jsr link +.e953 b0 08 bcs $e95d bcs _out +.e955 b9 44 03 lda $0344,y lda file.state,y +.e958 d0 04 bne $e95e bne _device +.e95a a9 03 lda #$03 lda #FILE_NOT_OPEN +.e95c 38 sec sec +.e95d 60 rts _out rts + +.e95e _device +.e95e b9 45 03 lda $0345,y lda file.device,y +.e961 c9 08 cmp #$08 cmp #8 +.e963 90 02 bcc $e967 bcc _found +.e965 a9 08 lda #$08 lda #8 + +.e967 _found +.e967 0a asl a asl a +.e968 0a asl a asl a +.e969 0a asl a asl a +.e96a aa tax tax +.e96b 60 rts rts + +.e96c link: + ; IN: A = logical file # + ; SUCCESS: + ; Carry clear + ; Y->file entry + ; FAIL: + ; Carry set + ; A = TOO_MANY_FILES + +.e96c c9 0a cmp #$0a cmp #MAX_FILES +.e96e 90 04 bcc $e974 bcc _link +.e970 a9 01 lda #$01 lda #TOO_MANY_FILES +.e972 38 sec sec +.e973 60 rts rts + +.e974 0a asl a _link asl a +.e975 0a asl a asl a +.e976 0a asl a asl a +.e977 a8 tay tay +.e978 60 rts rts + +.e979 error +.e979 20 b0 e9 jsr $e9b0 jsr dump +.e97c 48 pha pha +.e97d 5a phy phy +.e97e 48 pha pha +.e97f a0 00 ldy #$00 ldy #0 +.e981 b9 9a e9 lda $e99a,y _loop lda _msg,y +.e984 f0 06 beq $e98c beq _number +.e986 20 b9 f9 jsr $f9b9 jsr platform.console.putc +.e989 c8 iny iny +.e98a 80 f5 bra $e981 bra _loop +.e98c 68 pla _number pla +.e98d 18 clc clc +.e98e 69 30 adc #$30 adc #'0' +.e990 20 b9 f9 jsr $f9b9 jsr platform.console.putc +.e993 20 a5 e9 jsr $e9a5 jsr crlf +.e996 7a ply ply +.e997 68 pla pla +.e998 38 sec sec +.e999 60 rts rts +>e99a 49 2f 4f 20 45 52 52 4f _msg .null "I/O ERROR " +>e9a2 52 20 00 + +.e9a5 crlf +.e9a5 a9 0a lda #$0a lda #$0a +.e9a7 20 b9 f9 jsr $f9b9 jsr platform.console.putc +.e9aa a9 0d lda #$0d lda #$0d +.e9ac 20 b9 f9 jsr $f9b9 jsr platform.console.putc +.e9af 60 rts rts + +.e9b0 dump +.e9b0 48 pha pha +.e9b1 da phx phx +.e9b2 5a phy phy +.e9b3 a9 0d lda #$0d lda #$0d +.e9b5 20 b9 f9 jsr $f9b9 jsr platform.console.putc +.e9b8 a0 00 ldy #$00 ldy #0 +.e9ba b9 44 03 lda $0344,y _loop lda files,y +.e9bd 20 d3 e9 jsr $e9d3 jsr _pb +.e9c0 c8 iny iny +.e9c1 98 tya tya +.e9c2 29 07 and #$07 and #$07 +.e9c4 d0 f4 bne $e9ba bne _loop +.e9c6 a9 0d lda #$0d lda #$0d +.e9c8 20 b9 f9 jsr $f9b9 jsr platform.console.putc +.e9cb c0 50 cpy #$50 cpy #80 +.e9cd d0 eb bne $e9ba bne _loop + +.e9cf 7a ply ply +.e9d0 fa plx plx +.e9d1 68 pla pla +.e9d2 60 rts rts +.e9d3 _pb +.e9d3 48 pha pha +.e9d4 4a lsr a lsr a +.e9d5 4a lsr a lsr a +.e9d6 4a lsr a lsr a +.e9d7 4a lsr a lsr a +.e9d8 20 e6 e9 jsr $e9e6 jsr _nibble +.e9db 68 pla pla +.e9dc 29 0f and #$0f and #$0f +.e9de 20 e6 e9 jsr $e9e6 jsr _nibble +.e9e1 a9 20 lda #$20 lda #' ' +.e9e3 4c b9 f9 jmp $f9b9 jmp platform.console.putc +.e9e6 _nibble +.e9e6 aa tax tax +.e9e7 bd ed e9 lda $e9ed,x lda _hex,x +.e9ea 4c b9 f9 jmp $f9b9 jmp platform.console.putc +>e9ed 30 31 32 33 34 35 36 37 _hex .null "0123456789abcdef" +>e9f5 38 39 61 62 63 64 65 66 00 + + + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +.e9fe ioinit +.e9fe 64 c0 stz $c0 stz scraping ; Not presently screen scraping. +.ea00 64 c2 stz $c2 stz quoted ; Not presently in a quoted string + + ; Init (zero) the files table +.ea02 a2 00 ldx #$00 ldx #0 +.ea04 9e 44 03 stz $0344,x _loop stz files,x +.ea07 e8 inx inx +.ea08 e0 50 cpx #$50 cpx #8 * MAX_FILES +.ea0a d0 f8 bne $ea04 bne _loop +.ea0c 4c 0f ea jmp $ea0f jmp reopen + +.ea0f reopen + ; Open keyboard as stdin +.ea0f a9 00 lda #$00 lda #0 ; stdin +.ea11 a2 00 ldx #$00 ldx #0 ; keyboard +.ea13 a0 00 ldy #$00 ldy #0 ; dummy sub-device +.ea15 20 32 ea jsr $ea32 jsr setlfs +.ea18 20 40 ea jsr $ea40 jsr open +.ea1b a2 00 ldx #$00 ldx #0 +.ea1d 20 7e ea jsr $ea7e jsr chkin + + ; Open screen as stdout +.ea20 a9 01 lda #$01 lda #1 ; stdout +.ea22 a2 03 ldx #$03 ldx #3 ; screen +.ea24 a0 00 ldy #$00 ldy #0 ; dummy sub-device +.ea26 20 32 ea jsr $ea32 jsr setlfs +.ea29 20 40 ea jsr $ea40 jsr open +.ea2c a2 01 ldx #$01 ldx #1 +.ea2e 20 88 ea jsr $ea88 jsr chkout + +.ea31 60 rts rts + + +.ea32 setlfs +.ea32 85 b0 sta $b0 sta cur_logical +.ea34 86 b1 stx $b1 stx cur_device +.ea36 84 b2 sty $b2 sty cur_addr +.ea38 60 rts rts + +.ea39 setnam +.ea39 85 af sta $af sta fname_len +.ea3b 86 ad stx $ad stx fname+0 +.ea3d 84 ae sty $ae sty fname+1 +.ea3f 60 rts rts + +.ea40 open +.ea40 a5 b0 lda $b0 lda cur_logical +.ea42 20 6c e9 jsr $e96c jsr link +.ea45 b0 07 bcs $ea4e bcs _error +.ea47 b9 44 03 lda $0344,y lda file.state,y +.ea4a f0 05 beq $ea51 beq _open +.ea4c a9 02 lda #$02 lda #FILE_OPEN +.ea4e 4c 79 e9 jmp $e979 _error jmp error + +.ea51 _open +.ea51 a5 b1 lda $b1 lda cur_device +.ea53 99 45 03 sta $0345,y sta file.device,y +.ea56 a5 b2 lda $b2 lda cur_addr +.ea58 99 46 03 sta $0346,y sta file.secondary,y + +.ea5b a5 b1 lda $b1 lda cur_device +.ea5d 0a asl a asl a +.ea5e 0a asl a asl a +.ea5f 0a asl a asl a +.ea60 aa tax tax + +.ea61 20 e5 eb jsr $ebe5 jsr open_x +.ea64 b0 e8 bcs $ea4e bcs _error +.ea66 60 rts rts + + +.ea67 close +.ea67 20 50 e9 jsr $e950 jsr find +.ea6a 90 03 bcc $ea6f bcc _close +.ea6c 4c 79 e9 jmp $e979 jmp error +.ea6f 4c f0 eb jmp $ebf0 _close jmp close_x + +.ea72 chk + ; IN: X = logical file ID + ; Reports and returns an error if the file is invalid. +.ea72 da phx phx +.ea73 8a txa txa +.ea74 20 50 e9 jsr $e950 jsr find +.ea77 90 03 bcc $ea7c bcc _out +.ea79 20 79 e9 jsr $e979 jsr error +.ea7c fa plx _out plx +.ea7d 60 rts rts + +.ea7e chkin +.ea7e 5a phy phy +.ea7f 20 72 ea jsr $ea72 jsr chk +.ea82 b0 02 bcs $ea86 bcs _out +.ea84 86 bc stx $bc stx cur_in +.ea86 7a ply _out ply +.ea87 60 rts rts +.ea88 chkout +.ea88 5a phy phy +.ea89 20 72 ea jsr $ea72 jsr chk +.ea8c b0 02 bcs $ea90 bcs _out +.ea8e 86 bd stx $bd stx cur_out +.ea90 7a ply _out ply +.ea91 60 rts rts + +.ea92 clrchn ; TODO: not sure how this is /supposed/ to work. +.ea92 18 clc clc +.ea93 60 rts rts +.ea94 5a phy phy + +.ea95 a5 bc lda $bc _stdin lda cur_in +.ea97 20 50 e9 jsr $e950 jsr find +.ea9a b0 03 bcs $ea9f bcs _stdout +.ea9c 20 f0 eb jsr $ebf0 jsr close_x + +.ea9f a5 bd lda $bd _stdout lda cur_out +.eaa1 20 50 e9 jsr $e950 jsr find +.eaa4 b0 03 bcs $eaa9 bcs _reset +.eaa6 20 f0 eb jsr $ebf0 jsr close_x + + ; Reset stdin/stdout to 0/1 +.eaa9 a2 00 ldx #$00 _reset ldx #0 +.eaab 20 7e ea jsr $ea7e jsr chkin +.eaae a2 01 ldx #$01 ldx #1 +.eab0 20 88 ea jsr $ea88 jsr chkout + +.eab3 18 clc clc +.eab4 7a ply ply +.eab5 60 rts rts + +.eab6 chrin +.eab6 da phx phx +.eab7 5a phy phy +.eab8 a5 bc lda $bc lda cur_in +.eaba 20 50 e9 jsr $e950 jsr find +.eabd b0 0f bcs $eace bcs _error + +.eabf b9 45 03 lda $0345,y lda file.device,y +.eac2 d0 05 bne $eac9 bne _read + +.eac4 20 d4 ea jsr $ead4 _screen jsr screen +.eac7 80 08 bra $ead1 bra _out + +.eac9 20 e8 eb jsr $ebe8 _read jsr read_x +.eacc 90 03 bcc $ead1 bcc _out +.eace _error +.eace 20 79 e9 jsr $e979 jsr error +.ead1 _out +.ead1 7a ply ply +.ead2 fa plx plx +.ead3 60 rts rts + +.ead4 screen + ; Resume an inprogress screen-scrape +.ead4 a5 c0 lda $c0 lda scraping +.ead6 d0 1e bne $eaf6 bne _next + + ; Begin screen editing +.ead8 a5 e3 lda $e3 lda platform.console.cur_x +.eada 85 c1 sta $c1 sta scrape_x ; Start of input +.eadc 85 c2 sta $c2 sta quoted ; Disables toupper if not at col zero + +.eade 20 d6 ec jsr $ecd6 _read jsr kernel.keyboard.deque +.eae1 90 05 bcc $eae8 bcc _key +.eae3 20 f8 e6 jsr $e6f8 jsr kernel.thread.yield +.eae6 80 f6 bra $eade bra _read + +.eae8 c9 0d cmp #$0d _key cmp #13 ; ENTER +.eaea f0 08 beq $eaf4 beq _scrape +.eaec 20 38 eb jsr $eb38 jsr emacs +.eaef 20 b9 f9 jsr $f9b9 jsr platform.console.putc +.eaf2 80 ea bra $eade bra _read + +.eaf4 _scrape +.eaf4 85 c0 sta $c0 sta scraping ; 13 (enter) is non-zero. +.eaf6 _next +.eaf6 a4 c1 ldy $c1 ldy scrape_x +.eaf8 c4 e3 cpy $e3 cpy platform.console.cur_x +.eafa d0 08 bne $eb04 bne _getchar +.eafc 64 c0 stz $c0 stz scraping +.eafe 64 c2 stz $c2 stz quoted +.eb00 a9 0d lda #$0d lda #13 +.eb02 80 26 bra $eb2a bra _okay + +.eb04 _getchar +.eb04 da phx phx +.eb05 a6 01 ldx $01 ldx $1 ; TODO: move to console driver. +.eb07 a9 02 lda #$02 lda #2 +.eb09 85 01 sta $01 sta $1 +.eb0b b1 e5 lda ($e5),y lda (platform.console.ptr),y +.eb0d 29 7f and #$7f and #$7f +.eb0f 86 01 stx $01 stx $1 +.eb11 fa plx plx + +.eb12 e6 c1 inc $c1 inc scrape_x +.eb14 c9 20 cmp #$20 cmp #32 +.eb16 90 de bcc $eaf6 bcc _next ; can't generate these +.eb18 c9 22 cmp #$22 cmp #$22 ; Quote +.eb1a f0 10 beq $eb2c beq _quote +.eb1c a6 c2 ldx $c2 ldx quoted +.eb1e d0 0a bne $eb2a bne _okay +.eb20 c9 7b cmp #$7b cmp #'z'+1 +.eb22 b0 06 bcs $eb2a bcs _okay +.eb24 c9 61 cmp #$61 cmp #'a' +.eb26 90 02 bcc $eb2a bcc _okay +.eb28 49 20 eor #$20 eor #$20 ; toupper +.eb2a _okay +.eb2a 18 clc clc +.eb2b 60 rts rts + +.eb2c _quote +.eb2c a5 c2 lda $c2 lda quoted +.eb2e 64 c2 stz $c2 stz quoted +.eb30 d0 02 bne $eb34 bne _ret +.eb32 e6 c2 inc $c2 inc quoted +.eb34 a9 22 lda #$22 _ret lda #$22 ; quote +.eb36 80 f2 bra $eb2a bra _okay + + map .macro key, ctrl + .endm +.eb38 emacs +.eb38 da phx phx +.eb39 a2 00 ldx #$00 ldx #0 +.eb3b dd 4d eb cmp $eb4d,x _loop cmp _map,x +.eb3e f0 08 beq $eb48 beq _found +.eb40 e8 inx inx +.eb41 e8 inx inx +.eb42 e0 0c cpx #$0c cpx #_end +.eb44 d0 f5 bne $eb3b bne _loop +.eb46 80 03 bra $eb4b bra _out +.eb48 bd 4e eb lda $eb4e,x _found lda _map+1,x +.eb4b fa plx _out plx +.eb4c 60 rts rts +.eb4d _map +>eb4d 96 01 .byte HOME, ('a' & 31) +>eb4f 97 05 .byte END, ('e' & 31) +>eb51 99 10 .byte UP, ('p' & 31) +>eb53 9a 0e .byte DOWN, ('n' & 31) +>eb55 9b 02 .byte LEFT, ('b' & 31) +>eb57 9c 06 .byte RIGHT, ('f' & 31) +=12 _end = * - _map + +.eb59 getin +.eb59 da phx phx +.eb5a a5 bc lda $bc lda cur_in +.eb5c 20 50 e9 jsr $e950 jsr find +.eb5f b0 05 bcs $eb66 bcs _error +.eb61 20 e8 eb jsr $ebe8 jsr read_x +.eb64 90 03 bcc $eb69 bcc _done +.eb66 20 79 e9 jsr $e979 _error jsr error +.eb69 fa plx _done plx +.eb6a 09 00 ora #$00 ora #0 +.eb6c 60 rts rts + +.eb6d chrout +.eb6d da phx phx +.eb6e 5a phy phy +.eb6f 48 pha pha +.eb70 a5 bd lda $bd lda cur_out +.eb72 20 50 e9 jsr $e950 jsr find +.eb75 90 06 bcc $eb7d bcc _okay +.eb77 7a ply ply ; drop the character +.eb78 20 79 e9 jsr $e979 jsr error +.eb7b 80 06 bra $eb83 bra _done +.eb7d 68 pla _okay pla +.eb7e 48 pha pha +.eb7f 20 ec eb jsr $ebec jsr write_x +.eb82 68 pla pla +.eb83 7a ply _done ply +.eb84 fa plx plx +.eb85 60 rts rts + +.eb86 clall +.eb86 5a phy phy + + ; Close all + ; Manually, to hide errors. +.eb87 a9 00 lda #$00 lda #0 +.eb89 48 pha _loop pha +.eb8a 20 50 e9 jsr $e950 jsr find +.eb8d b0 03 bcs $eb92 bcs _next +.eb8f 20 f0 eb jsr $ebf0 jsr close_x +.eb92 68 pla _next pla +.eb93 1a inc a inc a +.eb94 c9 0a cmp #$0a cmp #MAX_FILES +.eb96 d0 f1 bne $eb89 bne _loop + + ; Reset stdin/stdout +.eb98 20 0f ea jsr $ea0f jsr reopen +.eb9b 7a ply ply +.eb9c 60 rts rts + + + + .send + .endn + .endn + + + +;****** Processing input file: core/dev.asm + + ; OpenKERNAL - a clean-room implementation of the C64's KERNAL ABI. + ; Copyright 2022 Jessie Oberreuter . + ; SPDX-License-Identifier: GPL-3.0-only + + .cpu "w65c02" + + .namespace kernel + io .namespace + .section kernel + + mkdev .macro DEV + .endm + +.eb9d devices +>eb9d 1b ec 21 ec 25 ec 1e ec .word keyboard_open, keyboard_stat, keyboard_io, keyboard_close +>eba5 f3 eb f3 eb f3 eb f3 eb .word missing_open, missing_stat, missing_io, missing_close +>ebad f3 eb f3 eb f3 eb f3 eb .word missing_open, missing_stat, missing_io, missing_close +>ebb5 06 ec 0c ec 10 ec 09 ec .word screen_open, screen_stat, screen_io, screen_close +>ebbd f3 eb f3 eb f3 eb f3 eb .word missing_open, missing_stat, missing_io, missing_close +>ebc5 f3 eb f3 eb f3 eb f3 eb .word missing_open, missing_stat, missing_io, missing_close +>ebcd f3 eb f3 eb f3 eb f3 eb .word missing_open, missing_stat, missing_io, missing_close +>ebd5 f3 eb f3 eb f3 eb f3 eb .word missing_open, missing_stat, missing_io, missing_close +>ebdd f3 eb f3 eb f3 eb f3 eb .word missing_open, missing_stat, missing_io, missing_close + + device .namespace + .virtual devices +>eb9d open .word ? +>eb9f stat .word ? +>eba1 io .word ? +>eba3 close .word ? + .endv + .endn + +.ebe5 7c 9d eb jmp ($eb9d,x) open_x jmp (device.open,x) +.ebe8 18 clc read_x clc +.ebe9 7c a1 eb jmp ($eba1,x) jmp (device.io,x) +.ebec 38 sec write_x sec +.ebed 7c a1 eb jmp ($eba1,x) jmp (device.io,x) +.ebf0 7c a3 eb jmp ($eba3,x) close_x jmp (device.close,x) + +.ebf3 missing_open +.ebf3 missing_stat +.ebf3 missing_io +.ebf3 missing_close +.ebf3 a9 05 lda #$05 lda #DEVICE_NOT_PRESENT +.ebf5 4c 79 e9 jmp $e979 jmp error + +.ebf8 simple_open +.ebf8 a9 01 lda #$01 lda #1 ; open +.ebfa 99 44 03 sta $0344,y sta file.state,y +.ebfd 18 clc clc +.ebfe 60 rts rts + +.ebff simple_close +.ebff a9 00 lda #$00 lda #0 +.ec01 99 44 03 sta $0344,y sta file.state,y +.ec04 18 clc clc +.ec05 60 rts rts + + + .send + .endn + .endn + + + +;****** Processing input file: core/dev_screen.asm + + ; OpenKERNAL - a clean-room implementation of the C64's KERNAL ABI. + ; Copyright 2022 Jessie Oberreuter . + ; SPDX-License-Identifier: GPL-3.0-only + + .cpu "w65c02" + + .namespace kernel + .namespace io + + .section kernel + + + +.ec06 screen_open +.ec06 4c f8 eb jmp $ebf8 jmp simple_open + +.ec09 screen_close +.ec09 4c ff eb jmp $ebff jmp simple_close + +.ec0c screen_stat +.ec0c a9 00 lda #$00 lda #0 +.ec0e 18 clc clc +.ec0f 60 rts rts + +.ec10 screen_io +.ec10 b0 04 bcs $ec16 bcs _write +.ec12 a9 00 lda #$00 lda #0 +.ec14 18 clc clc +.ec15 60 rts rts +.ec16 20 b9 f9 jsr $f9b9 _write jsr platform.console.putc +.ec19 18 clc clc +.ec1a 60 rts rts + + + .send + .endn + .endn + + +;****** Processing input file: core/dev_keyboard.asm + + ; OpenKERNAL - a clean-room implementation of the C64's KERNAL ABI. + ; Copyright 2022 Jessie Oberreuter . + ; SPDX-License-Identifier: GPL-3.0-only + + .cpu "w65c02" + + .namespace kernel + .namespace io + + .section kernel + +.ec1b keyboard_open +.ec1b 4c f8 eb jmp $ebf8 jmp simple_open + +.ec1e keyboard_close +.ec1e 4c ff eb jmp $ebff jmp simple_close + +.ec21 keyboard_stat +.ec21 a9 00 lda #$00 lda #0 +.ec23 18 clc clc +.ec24 60 rts rts + +.ec25 keyboard_io +.ec25 b0 09 bcs $ec30 bcs _write +.ec27 20 d6 ec jsr $ecd6 _loop jsr keyboard.deque +.ec2a 90 03 bcc $ec2f bcc _out +.ec2c a9 00 lda #$00 lda #0 +.ec2e 18 clc clc +.ec2f 60 rts _out rts +.ec30 a9 07 lda #$07 _write lda #NOT_OUTPUT_FILE +.ec32 4c 79 e9 jmp $e979 jmp error + + .send + .endn + .endn + + + +;****** Processing input file: core/rtc.asm + + ; OpenKERNAL - a clean-room implementation of the C64's KERNAL ABI. + ; Copyright 2022 Jessie Oberreuter . + ; SPDX-License-Identifier: GPL-3.0-only + + .cpu "65c02" + + .namespace kernel + .section kernel + +.ec35 settim +.ec35 rdtim +.ec35 udtim +.ec35 18 clc clc +.ec36 60 rts rts + + .send + .endn + + +;****** Processing input file: core/sys.asm + + ; OpenKERNAL - a clean-room implementation of the C64's KERNAL ABI. + ; Copyright 2022 Jessie Oberreuter . + ; SPDX-License-Identifier: GPL-3.0-only + + .cpu "w65c02" + + .namespace kernel + .section kernel + + +.ec37 ramtas + +.ec37 a2 02 ldx #$02 ldx #2 +.ec39 74 00 stz $00,x _11 stz $0,x +.ec3b e8 inx inx +.ec3c e0 a3 cpx #$a3 cpx #free_mem +.ec5e 18 clc clc ; set +.ec5f 20 7a ec jsr $ec7a jsr memtop + +.ec62 a2 00 ldx #$00 ldx #0 +.ec64 a0 a0 ldy #$a0 ldy #>basic +.ec66 18 clc clc ; set +.ec67 20 6e ec jsr $ec6e jsr membot + +.ec6a 60 rts rts + + +.ec6b setmsg +.ec6b 85 b7 sta $b7 sta msg_switch +.ec6d 60 rts rts + +.ec6e membot +.ec6e 90 05 bcc $ec75 bcc _save + +.ec70 a6 b5 ldx $b5 _load ldx mem_end+0 +.ec72 a4 b6 ldy $b6 ldy mem_end+1 +.ec74 60 rts rts + +.ec75 86 b5 stx $b5 _save stx mem_end+0 +.ec77 84 b6 sty $b6 sty mem_end+1 +.ec79 60 rts rts + +.ec7a memtop +.ec7a 90 05 bcc $ec81 bcc _save + +.ec7c a6 b3 ldx $b3 _load ldx mem_start+0 +.ec7e a4 b4 ldy $b4 ldy mem_start+1 +.ec80 60 rts rts + +.ec81 86 b3 stx $b3 _save stx mem_start+0 +.ec83 84 b4 sty $b4 sty mem_start+1 +.ec85 60 rts rts + + + +.ec86 scnkey + ; PS2 keyboard is interrupt driven. + ; May be used to force a CIA scan. +.ec86 60 rts rts + +.ec87 iobase +.ec87 a2 dc ldx #$dc ldx #$dc +.ec89 a0 00 ldy #$00 ldy #$00 +.ec8b 60 rts rts + + + .send + .endn + + + + + +;****** Processing input file: core/keyboard.asm + + ; OpenKERNAL - a clean-room implementation of the C64's KERNAL ABI. + ; Copyright 2022 Jessie Oberreuter . + ; SPDX-License-Identifier: GPL-3.0-only + + .cpu "w65c02" + + .namespace kernel + keyboard .namespace + + .section kmem +>0394 head .byte ? +>0395 tail .byte ? +>0396 ctrl_c .byte ? + .send + +=16 BUF_SIZE = 16 + + .section kbuf +>0334 buf .fill BUF_SIZE + .send + + .section kernel + +.ec8c init +.ec8c 9c 94 03 stz $0394 stz head +.ec8f 9c 95 03 stz $0395 stz tail +.ec92 9c 96 03 stz $0396 stz ctrl_c +.ec95 60 rts rts +.ec96 stop + ; See if a ctrl_c has been queued. +.ec96 ad 96 03 lda $0396 lda ctrl_c +.ec99 d0 04 bne $ec9f bne _stop + + ; No stop detected. +.ec9b a9 ff lda #$ff lda #$ff +.ec9d 18 clc clc +.ec9e 60 rts rts + +.ec9f _stop + ; Nominally reset the I/O paths. +.ec9f 20 cc ff jsr $ffcc jsr CLRCHN + + ; Flush the keyboard queue. +.eca2 78 sei sei +.eca3 9c 94 03 stz $0394 stz head +.eca6 9c 95 03 stz $0395 stz tail +.eca9 58 cli cli + + ; Clear the ctrl_c condition. +.ecaa 9c 96 03 stz $0396 stz ctrl_c + + ; Return 'stopped' status. +.ecad a9 00 lda #$00 lda #0 +.ecaf 38 sec sec +.ecb0 60 rts rts + +.ecb1 enque + ; A = character to enqueue. + ; Carry set if the queue is full. + ; Code is thread-safe to support multiple event sources. + +.ecb1 c9 03 cmp #$03 cmp #3 ; ctrl_c +.ecb3 d0 03 bne $ecb8 bne _enque +.ecb5 8d 96 03 sta $0396 sta ctrl_c +.ecb8 _enque +.ecb8 da phx phx +.ecb9 38 sec sec ; Pre-emptively set carry +.ecba 08 php php ; Carry is on the stack. +.ecbb 78 sei sei +.ecbc ae 94 03 ldx $0394 ldx head +.ecbf 9d 34 03 sta $0334,x sta buf,x +.ecc2 ca dex dex +.ecc3 10 02 bpl $ecc7 bpl _ok +.ecc5 a2 0f ldx #$0f ldx #BUF_SIZE-1 +.ecc7 ec 95 03 cpx $0395 _ok cpx tail +.ecca f0 07 beq $ecd3 beq _out +.eccc 8e 94 03 stx $0394 stx head +.eccf ba tsx tsx +.ecd0 de 01 01 dec $0101,x dec Stack+1,x ; Clear carry +.ecd3 28 plp _out plp +.ecd4 fa plx plx +.ecd5 60 rts rts + + +.ecd6 deque + ; A <- character, or carry set on empty. + ; Not thread safe, as the KERNAL calls are not thread safe. +.ecd6 da phx phx +.ecd7 ae 95 03 ldx $0395 ldx tail +.ecda ec 94 03 cpx $0394 cpx head +.ecdd 38 sec sec +.ecde f0 0c beq $ecec beq _out +.ece0 bd 34 03 lda $0334,x lda buf,x +.ece3 ca dex dex +.ece4 10 02 bpl $ece8 bpl _ok +.ece6 a2 0f ldx #$0f ldx #BUF_SIZE-1 +.ece8 8e 95 03 stx $0395 _ok stx tail +.eceb 18 clc clc +.ecec fa plx _out plx +.eced 60 rts rts + + .send + .endn + .endn + + +;****** Processing input file: core/video.asm + + ; OpenKERNAL - a clean-room implementation of the C64's KERNAL ABI. + ; Copyright 2022 Jessie Oberreuter . + ; SPDX-License-Identifier: GPL-3.0-only + + .cpu "65c02" + + .namespace kernel + .section kernel + +.ecee scinit +.ecee 4c e4 f7 jmp $f7e4 jmp platform.console.init + +.ecf1 screen +.ecf1 a2 50 ldx #$50 ldx #platform.console.COLS +.ecf3 a0 3c ldy #$3c ldy #platform.console.ROWS +.ecf5 60 rts rts + +.ecf6 plot +.ecf6 b0 03 bcs $ecfb bcs _fetch +.ecf8 20 49 f9 jsr $f949 jsr platform.console.gotoxy +.ecfb a6 e3 ldx $e3 _fetch ldx platform.console.cur_x +.ecfd a6 e4 ldx $e4 ldx platform.console.cur_y +.ecff 60 rts rts + + .send + .endn + + +;****** Processing input file: core/device.asm + + ; OpenKERNAL - a clean-room implementation of the C64's KERNAL ABI. + ; Copyright 2022 Jessie Oberreuter . + ; SPDX-License-Identifier: GPL-3.0-only + + ; This file is from the w6502c TinyCore kernel by the same author. + + .cpu "w65c02" + + .namespace kernel + + dev .namespace + .virtual Devices + + ; External functions +>0400 data .word ? ; Data ready +>0402 status .word ? ; Status change +>0404 fetch .word ? ; Device requests data to send + + ; Internal functions +>0406 open .word ? ; Call to open device +>0408 get .word ? ; Call to get device data +>040a set .word ? ; Call to set device data +>040c send .word ? ; Call to send data +>040e close .word ? ; Call to close device +.0410 size .endv + .endn + + device .namespace + + mkdev .macro PREFIX + .endm + + .section kmem +>0397 entries .byte ? ; List of free device entries + .send + + .section kernel + +.ed00 7c 00 04 jmp ($0400,x) data jmp (kernel.dev.data,x) +.ed03 7c 02 04 jmp ($0402,x) status jmp (kernel.dev.status,x) +.ed06 7c 04 04 jmp ($0404,x) fetch jmp (kernel.dev.fetch,x) +.ed09 7c 06 04 jmp ($0406,x) open jmp (kernel.dev.open,x) +.ed0c 7c 08 04 jmp ($0408,x) get jmp (kernel.dev.get,x) +.ed0f 7c 0a 04 jmp ($040a,x) set jmp (kernel.dev.set,x) +.ed12 7c 0c 04 jmp ($040c,x) send jmp (kernel.dev.send,x) +.ed15 7c 0e 04 jmp ($040e,x) close jmp (kernel.dev.close,x) + +.ed18 init +.ed18 9c 97 03 stz $0397 stz entries +.ed1b a9 00 lda #$00 lda #0 +.ed1d 80 04 bra $ed23 bra _next ; Reserve the first one. +.ed1f aa tax _loop tax +.ed20 20 3a ed jsr $ed3a jsr free +.ed23 18 clc _next clc +.ed24 69 10 adc #$10 adc #0500 head .byte ? +>0501 tail .byte ? + .endv + +.ed5c init +.ed5c 9e 00 05 stz $0500,x stz head,x +.ed5f 9e 01 05 stz $0501,x stz tail,x +.ed62 60 rts rts + +.ed63 enque + ; X = queue, Y = token + +.ed63 48 pha pha +.ed64 08 php php +.ed65 78 sei sei +.ed66 bd 01 05 lda $0501,x lda tail,x +.ed69 99 03 02 sta $0203,y sta kernel.token.entry.next,y +.ed6c 98 tya tya +.ed6d 9d 01 05 sta $0501,x sta tail,x +.ed70 28 plp plp +.ed71 68 pla pla +.ed72 18 clc clc +.ed73 60 rts rts + +.ed74 deque + ; OUT: Y = dequed token; carry set on empty + +.ed74 48 pha pha + +.ed75 bc 00 05 ldy $0500,x ldy head,x +.ed78 d0 23 bne $ed9d bne _found + +.ed7a 38 sec sec +.ed7b bc 01 05 ldy $0501,x ldy tail,x +.ed7e f0 24 beq $eda4 beq _out + + ; Safely take the tail (into y) +.ed80 08 php php +.ed81 78 sei sei +.ed82 bc 01 05 ldy $0501,x ldy tail,x +.ed85 9e 01 05 stz $0501,x stz tail,x +.ed88 28 plp plp + + ; Reverse into head +.ed89 b9 03 02 lda $0203,y _loop lda kernel.token.entry.next,y ; next in A +.ed8c 48 pha pha ; next on stack +.ed8d bd 00 05 lda $0500,x lda head,x +.ed90 99 03 02 sta $0203,y sta kernel.token.entry.next,y +.ed93 98 tya tya +.ed94 9d 00 05 sta $0500,x sta head,x +.ed97 7a ply ply ; next in Y +.ed98 d0 ef bne $ed89 bne _loop + + ; "Find" the head (just where we left it) +.ed9a bc 00 05 ldy $0500,x ldy head,x + +.ed9d _found +.ed9d b9 03 02 lda $0203,y lda kernel.token.entry.next,y +.eda0 9d 00 05 sta $0500,x sta head,x +.eda3 18 clc clc + +.eda4 68 pla _out pla +.eda5 60 rts rts + + .endn + .send + .endn + .endn + + +;****** Processing input file: core/token.asm + + ; OpenKERNAL - a clean-room implementation of the C64's KERNAL ABI. + ; Copyright 2022 Jessie Oberreuter . + ; SPDX-License-Identifier: GPL-3.0-only + + ; This file is from the w6502c TinyCore kernel by the same author. + + .cpu "w65c02" + + .namespace kernel + token .namespace + + entry .namespace + .virtual Tokens +>0200 data .fill 3 +>0203 next .byte ? +.0204 end .endv +=4 size = end - Tokens + .endn + + .section kmem +>0398 entries .byte ? ; free list + .send + + .section kernel + +.eda6 init +.eda6 9c 98 03 stz $0398 stz entries +.eda9 a9 90 lda #$90 lda #. + ; SPDX-License-Identifier: GPL-3.0-only + + .cpu "65c02" + + .namespace kernel + .section kernel + + + + +.eddc ivec_start +>eddc 2c ee .word irq +>edde 2c ee .word break +>ede0 2c ee .word nmi +>ede2 40 ea .word io.open +>ede4 67 ea .word io.close +>ede6 7e ea .word io.chkin +>ede8 88 ea .word io.chkout +>edea 92 ea .word io.clrchn +>edec b6 ea .word io.chrin +>edee 6d eb .word io.chrout +>edf0 96 ec .word keyboard.stop +>edf2 59 eb .word io.getin +>edf4 86 eb .word io.clall +>edf6 2c ee .word user +>edf8 5a e8 .word iec.load +>edfa 7e e8 .word iec.save +.edfc ivec_end +=32 ivec_size = ivec_end - ivec_start + + + +.edfc restor +.edfc 48 pha pha +.edfd da phx phx +.edfe a2 00 ldx #$00 ldx #0 +.ee00 bd dc ed lda $eddc,x _loop lda ivec_start,x +.ee03 9d 14 03 sta $0314,x sta $314,x +.ee06 e8 inx inx +.ee07 c9 20 cmp #$20 cmp #ivec_size +.ee09 d0 f5 bne $ee00 bne _loop +.ee0b fa plx plx +.ee0c 68 pla pla +.ee0d 60 rts rts + +.ee0e vector +.ee0e 86 a5 stx $a5 stx src+0 +.ee10 84 a6 sty $a6 sty src+1 + +.ee12 a0 00 ldy #$00 ldy #0 +.ee14 b0 0b bcs $ee21 bcs _out + +.ee16 b1 a5 lda ($a5),y _in lda (src),y +.ee18 99 14 03 sta $0314,y sta $314,y +.ee1b c8 iny iny +.ee1c c0 20 cpy #$20 cpy #ivec_size +.ee1e d0 f6 bne $ee16 bne _in +.ee20 60 rts rts + +.ee21 b9 14 03 lda $0314,y _out lda $314,y +.ee24 91 a5 sta ($a5),y sta (src),y +.ee26 c8 iny iny +.ee27 c0 20 cpy #$20 cpy #ivec_size +.ee29 d0 f6 bne $ee21 bne _out +.ee2b 60 rts rts + + + +.ee2c irq +.ee2c break +.ee2c nmi +.ee2c user +.ee2c 38 sec sec +.ee2d 60 rts rts + + + .send + .endn + + +;****** Processing input file: core/cli.asm + + ; OpenKERNAL - a clean-room implementation of the C64's KERNAL ABI. + ; Copyright 2022 Jessie Oberreuter . + ; SPDX-License-Identifier: GPL-3.0-only + + ; Simple command-line interface for use when nothing else is included. + + .cpu "w65c02" + + .namespace kernel + shell .namespace + + .virtual Tokens ; $90 bytes here in page 2 +>0200 cmd .fill 80 + .endv + + .section dp +>00c3 str_ptr .word ? +>00c5 printing .word ? +>00c7 device .byte ? + .send + + .section shell + +.e000 strings: + str .namespace +>e000 3f 0d 00 unknown .text "?", 13, 0 +>e003 0d 52 45 41 44 59 20 44 prompt .text 13,"READY DEVICE",0 +>e00b 45 56 49 43 45 00 +>e011 44 49 52 00 dir .null "DIR" +>e015 53 54 41 54 00 stat .null "STAT" +>e01a 52 44 53 00 rds .null "RDS" +>e01e 43 4c 53 00 cls .null "CLS" +>e022 4c 49 53 54 00 list .null "LIST" +>e027 4c 4f 41 44 00 load .null "LOAD" +>e02c 44 52 49 56 45 00 drive .null "DRIVE" +>e032 52 55 4e 00 run .null "RUN" +>e036 53 59 53 00 sys .null "SYS" +>e03a 48 45 4c 50 00 help .null "HELP" +>e03f 0d 54 79 70 65 20 27 68 intro .text 13,"Type 'help' for help.",13,0 +>e047 65 6c 70 27 20 66 6f 72 20 68 65 6c 70 2e 0d 00 + .endn + +.e057 help_text +>e057 0d 53 75 70 70 6f 72 74 .text 13,"Supported commands:",13 +>e05f 65 64 20 63 6f 6d 6d 61 6e 64 73 3a 0d +>e06c 20 20 20 63 6c 73 20 20 .text " cls Clears the screen.",13 +>e074 20 20 20 20 20 20 20 43 6c 65 61 72 73 20 74 68 +>e084 65 20 73 63 72 65 65 6e 2e 0d +>e08e 20 20 20 64 72 69 76 65 .text " drive # Changes the drive to #.",13 +>e096 20 23 20 20 20 20 20 43 68 61 6e 67 65 73 20 74 +>e0a6 68 65 20 64 72 69 76 65 20 74 6f 20 23 2e 0d +>e0b5 20 20 20 64 69 72 20 20 .text " dir Displays the directory.",13 +>e0bd 20 20 20 20 20 20 20 44 69 73 70 6c 61 79 73 20 +>e0cd 74 68 65 20 64 69 72 65 63 74 6f 72 79 2e 0d +>e0dc 20 20 20 6c 6f 61 64 22 .text " load",$22,"fname",$22," Loads the given file ',1'.", 13 +>e0e4 66 6e 61 6d 65 22 20 4c 6f 61 64 73 20 74 68 65 +>e0f4 20 67 69 76 65 6e 20 66 69 6c 65 20 27 2c 31 27 +>e104 2e 0d +>e106 20 20 20 6c 69 73 74 20 .text " list LISTs directories and simple programs.",13 +>e10e 20 20 20 20 20 20 20 4c 49 53 54 73 20 64 69 72 +>e11e 65 63 74 6f 72 69 65 73 20 61 6e 64 20 73 69 6d +>e12e 70 6c 65 20 70 72 6f 67 72 61 6d 73 2e 0d +>e13c 20 20 20 72 75 6e 20 20 .text " run Runs loaded programs.",13 +>e144 20 20 20 20 20 20 20 52 75 6e 73 20 6c 6f 61 64 +>e154 65 64 20 70 72 6f 67 72 61 6d 73 2e 0d +>e161 20 20 20 68 65 6c 70 20 .text " help Shows this help.",13 +>e169 20 20 20 20 20 20 20 53 68 6f 77 73 20 74 68 69 +>e179 73 20 68 65 6c 70 2e 0d +>e181 0d 00 .text 13,0 + +.e183 commands +>e183 1e e0 35 e2 .word str.cls, cls +>e187 11 e0 6b e2 .word str.dir, dir +>e18b 22 e0 2e ee .word str.list, list +>e18f 27 e0 0e ef .word str.load, load +>e193 2c e0 4e e2 .word str.drive, drive +>e197 32 e0 c1 f2 .word str.run, platform.far_exec +>e19b 3a e0 a0 e1 .word str.help, help +>e19f 00 .byte 0 + +.e1a0 help +.e1a0 a9 57 lda #$57 lda #help_text +.e1a6 85 a6 sta $a6 sta src+1 +.e1a8 4c 16 e7 jmp $e716 jmp kernel.puts + +.e1ab start +.e1ab 20 0b e7 jsr $e70b jsr banner + +.e1ae a9 e0 lda #$e0 lda #>strings +.e1b0 85 c4 sta $c4 sta str_ptr+1 + +.e1b2 a0 3f ldy #$3f ldy #_fname +.e271 a9 01 lda #$01 lda #1 +.e273 20 bd ff jsr $ffbd jsr SETNAM + + ; Request operation on 0,device,0 +.e276 a9 00 lda #$00 lda #0 ; Logical device # ... not meaningful here. +.e278 a6 c7 ldx $c7 ldx device +.e27a a0 00 ldy #$00 ldy #0 ; No sub-device / "command" -> use $0801 +.e27c 20 ba ff jsr $ffba jsr SETLFS + + ; Load the data +.e27f a9 00 lda #$00 lda #0 ; load, not verify +.e281 a2 01 ldx #$01 ldx #<$801 +.e283 a0 08 ldy #$08 ldy #>$801 +.e285 20 d5 ff jsr $ffd5 jsr LOAD +.e288 b0 0d bcs $e297 bcs _out +.e28a 20 b7 ff jsr $ffb7 jsr READST +.e28d f0 05 beq $e294 beq _list +.e28f a9 05 lda #$05 lda #DEVICE_NOT_PRESENT +.e291 38 sec sec +.e292 80 03 bra $e297 bra _out + +.e294 _list + ; Show the data +.e294 20 2e ee jsr $ee2e jsr list +.e297 _out +.e297 7a ply ply +.e298 fa plx plx +.e299 60 rts rts +>e29a 24 _fname .text "$" + + + +.e29b putc + ; IN: A = character code +.e29b 4c b9 f9 jmp $f9b9 jmp platform.console.putc + +.e29e puts + ; IN: Y=LSB of a string in 'strings' above. +.e29e 84 c3 sty $c3 sty str_ptr +.e2a0 a0 00 ldy #$00 ldy #0 +.e2a2 b1 c3 lda ($c3),y _loop lda (str_ptr),y +.e2a4 f0 06 beq $e2ac beq _out +.e2a6 20 9b e2 jsr $e29b jsr putc +.e2a9 c8 iny iny +.e2aa 80 f6 bra $e2a2 bra _loop +.e2ac _out +.e2ac 18 clc clc +.e2ad 60 rts rts + + + .send + .endn + .endn + + + .if false + .endif + + + +;****** Processing input file: core/cli_list.asm + + ; OpenKERNAL - a clean-room implementation of the C64's KERNAL ABI. + ; Copyright 2022 Jessie Oberreuter . + ; SPDX-License-Identifier: GPL-3.0-only + + ; Simple command-line interface for use when nothing else is included. + + .cpu "w65c02" + + .namespace kernel + .namespace shell + + .section kernel +.ee2e list +.ee2e 20 d7 e1 jsr $e1d7 jsr cr + +.ee31 da phx phx +.ee32 5a phy phy + +.ee33 a2 00 ldx #$00 ldx #0 ; count MSB +.ee35 a0 00 ldy #$00 ldy #0 ; count LSB + +.ee37 a9 01 lda #$01 lda #<$801 +.ee39 85 a5 sta $a5 sta src+0 +.ee3b a9 08 lda #$08 lda #>$801 +.ee3d 85 a6 sta $a6 sta src+1 + +.ee3f _line + ; File ends when the would-be next address is zero. +.ee3f 20 7e ee jsr $ee7e jsr _fetch +.ee42 85 ab sta $ab sta tos_l ; tmp +.ee44 20 7e ee jsr $ee7e jsr _fetch +.ee47 05 ab ora $ab ora tos_l +.ee49 f0 3d beq $ee88 beq _done + + ; Fetch the line number +.ee4b 20 7e ee jsr $ee7e jsr _fetch +.ee4e 85 ab sta $ab sta tos_l +.ee50 20 7e ee jsr $ee7e jsr _fetch +.ee53 85 ac sta $ac sta tos_h + + ; Print the line number +.ee55 20 8c ee jsr $ee8c jsr print_number + + ; Print the rest of the line +.ee58 _loop +.ee58 20 7e ee jsr $ee7e jsr _fetch +.ee5b f0 1c beq $ee79 beq _eol +.ee5d 30 06 bmi $ee65 bmi _ext +.ee5f c9 20 cmp #$20 cmp #32 +.ee61 b0 11 bcs $ee74 bcs _putc +.ee63 80 0d bra $ee72 bra _fill +.ee65 c9 9e cmp #$9e _ext cmp #$9e +.ee67 f0 02 beq $ee6b beq _sys +.ee69 80 07 bra $ee72 bra _fill +.ee6b _sys +.ee6b 5a phy phy +.ee6c a0 36 ldy #$36 ldy #eee5 10 27 e8 03 64 00 0a 00 .word 10000, 1000, 100, 10, 1 +>eeed 01 00 + + .send + .endn + .endn + + + +;****** Processing input file: core/cli_load.asm + + ; OpenKERNAL - a clean-room implementation of the C64's KERNAL ABI. + ; Copyright 2022 Jessie Oberreuter . + ; SPDX-License-Identifier: GPL-3.0-only + + ; Simple command-line interface for use when nothing else is included. + + .cpu "w65c02" + + .namespace kernel + .namespace shell + + .section dp +>00c8 far_addr .fill 4 +>00cc far_dest .fill 4 +>00d0 far_count .fill 4 +>00d4 addr_len .byte ? + .send + + .section kernel + +.eeef extensions +>eeef 50 52 47 8f ef .text "PRG", load_prg +>eef4 70 72 67 8f ef .text "prg", load_prg +>eef9 50 47 58 4c f0 .text "PGX", load_pgx +>eefe 70 67 78 4c f0 .text "pgx", load_pgx +>ef03 50 47 5a d2 f0 .text "PGZ", load_pgz +>ef08 70 67 7a d2 f0 .text "pgz", load_pgz +>ef0d 00 .byte 0 + +.ef0e load +.ef0e 64 c8 stz $c8 stz far_addr+0 +.ef10 64 c9 stz $c9 stz far_addr+1 + +.ef12 20 3c e2 jsr $e23c jsr find_arg +.ef15 90 01 bcc $ef18 bcc _quote +.ef17 60 rts rts + +.ef18 _quote +.ef18 20 37 ef jsr $ef37 jsr set_fname +.ef1b b0 19 bcs $ef36 bcs _out + +.ef1d a5 af lda $af lda fname_len +.ef1f c9 05 cmp #$05 cmp #5 ; has an extension? +.ef21 90 10 bcc $ef33 bcc _prg ; No, default to prg. + + ; Y = start of extension (starting with the '.'). +.ef23 a5 af lda $af lda fname_len +.ef25 38 sec sec +.ef26 e9 04 sbc #$04 sbc #4 ; should be start of ext +.ef28 a8 tay tay + + ; Does it start with a '.'? +.ef29 b1 ad lda ($ad),y lda (fname),y +.ef2b c9 2e cmp #$2e cmp #'.' +.ef2d d0 04 bne $ef33 bne _prg ; No, default to prg. + +.ef2f c8 iny iny +.ef30 4c 5a ef jmp $ef5a jmp load_by_extension +.ef33 4c 8f ef jmp $ef8f _prg jmp load_prg +.ef36 60 rts _out rts + + +.ef37 set_fname +.ef37 c8 iny iny +.ef38 5a phy phy +.ef39 b9 00 02 lda $0200,y _loop lda cmd,y +.ef3c c9 22 cmp #$22 cmp #$22 ; Quote +.ef3e f0 0a beq $ef4a beq _setnam +.ef40 c9 0d cmp #$0d cmp #13 +.ef42 f0 03 beq $ef47 beq _error +.ef44 c8 iny iny +.ef45 d0 f2 bne $ef39 bne _loop +.ef47 _error +.ef47 38 sec sec +.ef48 _done +.ef48 7a ply ply +.ef49 60 rts rts + +.ef4a _setnam + ; A = length of string +.ef4a 98 tya tya +.ef4b ba tsx tsx +.ef4c 38 sec sec +.ef4d fd 01 01 sbc $0101,x sbc $101,x ; Start of string (on stack) +.ef50 f0 f5 beq $ef47 beq _error + + ; X = LSB of string +.ef52 fa plx plx + + ; Y = MSB of string +.ef53 a0 02 ldy #$02 ldy #>cmd + +.ef55 20 bd ff jsr $ffbd jsr SETNAM +.ef58 18 clc clc +.ef59 60 rts rts + +.ef5a load_by_extension + +.ef5a a2 00 ldx #$00 ldx #0 +.ef5c bd ef ee lda $eeef,x _loop lda extensions,x +.ef5f f0 0e beq $ef6f beq _failed +.ef61 20 73 ef jsr $ef73 jsr _cmp +.ef64 90 06 bcc $ef6c bcc _found +.ef66 8a txa txa +.ef67 69 04 adc #$04 adc #4 ; 5 with the carry +.ef69 aa tax tax +.ef6a 80 f0 bra $ef5c bra _loop +.ef6c 7c f2 ee jmp ($eef2,x) _found jmp (extensions+3,x) +.ef6f _failed +.ef6f a9 04 lda #$04 lda #4 ; TODO +.ef71 38 sec sec +.ef72 60 rts rts +.ef73 _cmp +.ef73 5a phy phy +.ef74 38 sec sec + +.ef75 b1 ad lda ($ad),y lda (fname),y +.ef77 5d ef ee eor $eeef,x eor extensions+0,x +.ef7a d0 11 bne $ef8d bne _out + +.ef7c c8 iny iny +.ef7d b1 ad lda ($ad),y lda (fname),y +.ef7f 5d f0 ee eor $eef0,x eor extensions+1,x +.ef82 d0 09 bne $ef8d bne _out + +.ef84 c8 iny iny +.ef85 b1 ad lda ($ad),y lda (fname),y +.ef87 5d f1 ee eor $eef1,x eor extensions+2,x +.ef8a d0 01 bne $ef8d bne _out + +.ef8c 18 clc clc +.ef8d _out +.ef8d 7a ply ply +.ef8e 60 rts rts + + +.ef8f load_prg + + ; Set Y=0 for fname == "$", Y=1 (binary) otherwise. +.ef8f a0 01 ldy #$01 ldy #1 +.ef91 a5 af lda $af lda fname_len +.ef93 c9 01 cmp #$01 cmp #1 +.ef95 d0 09 bne $efa0 bne _setlfs +.ef97 b2 ad lda ($ad) lda (fname) +.ef99 c9 24 cmp #$24 cmp #'$' +.ef9b d0 03 bne $efa0 bne _setlfs +.ef9d 4c 6b e2 jmp $e26b jmp dir + +.efa0 _setlfs +.efa0 a9 00 lda #$00 lda #0 ; Logical device # ... not meaningful here. +.efa2 a6 c7 ldx $c7 ldx device +.efa4 a0 01 ldy #$01 ldy #1 ; Use native load address +.efa6 20 ba ff jsr $ffba jsr SETLFS + + ; Load the data +.efa9 a9 00 lda #$00 lda #0 ; load, not verify +.efab 20 d5 ff jsr $ffd5 jsr LOAD +.efae b0 03 bcs $efb3 bcs _out + +.efb0 4c b4 ef jmp $efb4 jmp find_sys + +.efb3 60 rts _out rts + +.efb4 find_sys + + ; Copy the embedded load address to far_addr +.efb4 a5 a5 lda $a5 lda src+0 +.efb6 85 c8 sta $c8 sta far_addr+0 +.efb8 a5 a6 lda $a6 lda src+1 +.efba 85 c9 sta $c9 sta far_addr+1 + + ; If the embedded address is not $801, it is the start addr. +.efbc a5 a5 lda $a5 lda src+0 +.efbe c9 01 cmp #$01 cmp #<$801 +.efc0 d0 49 bne $f00b bne _done + +.efc2 a5 a6 lda $a6 lda src+1 +.efc4 c9 08 cmp #$08 cmp #>$801 +.efc6 d0 43 bne $f00b bne _done + + ; BASIC header; get far_addr from a SYS call. +.efc8 64 c8 stz $c8 stz far_addr+0 +.efca 64 c9 stz $c9 stz far_addr+1 + + ; BASIC parser +.efcc a0 00 ldy #$00 ldy #0 +.efce _line + ; File ends when the would-be next address is zero. +.efce 20 01 f0 jsr $f001 jsr _fetch +.efd1 85 ab sta $ab sta tos_l ; tmp +.efd3 20 01 f0 jsr $f001 jsr _fetch +.efd6 05 ab ora $ab ora tos_l +.efd8 f0 31 beq $f00b beq _done + + ; Skip the line number +.efda 20 01 f0 jsr $f001 jsr _fetch +.efdd 20 01 f0 jsr $f001 jsr _fetch + + ; Scan the rest of the line +.efe0 _loop +.efe0 20 01 f0 jsr $f001 jsr _fetch +.efe3 f0 e9 beq $efce beq _line +.efe5 10 f9 bpl $efe0 bpl _loop +.efe7 c9 9e cmp #$9e cmp #$9e ; SYS +.efe9 d0 f5 bne $efe0 bne _loop + + ; SYS token found; skip any following spaces. +.efeb 20 01 f0 jsr $f001 _spaces jsr _fetch + ;beq _done + ;cmp #' ' + ;beq _spaces + + ; atoi the following digits. +.efee c9 30 cmp #$30 _digits cmp #'0' +.eff0 90 19 bcc $f00b bcc _done +.eff2 c9 3a cmp #$3a cmp #'9'+1 +.eff4 b0 15 bcs $f00b bcs _done +.eff6 38 sec sec +.eff7 e9 30 sbc #$30 sbc #'0' +.eff9 20 0d f0 jsr $f00d jsr mul_add +.effc 20 01 f0 jsr $f001 jsr _fetch +.efff 80 ed bra $efee bra _digits + +.f001 _fetch +.f001 b1 a5 lda ($a5),y lda (src),y +.f003 c8 iny iny +.f004 d0 02 bne $f008 bne _fetched +.f006 e6 a6 inc $a6 inc src+1 +.f008 _fetched +.f008 09 00 ora #$00 ora #0 +.f00a 60 rts rts + +.f00b _done +.f00b 18 clc clc +.f00c 60 rts rts + +.f00d mul_add + ; Multiply far_addr by 10. +.f00d 48 pha pha +.f00e 20 2a f0 jsr $f02a jsr _copy +.f011 20 33 f0 jsr $f033 jsr _x2 +.f014 20 33 f0 jsr $f033 jsr _x2 +.f017 20 3e f0 jsr $f03e jsr _add +.f01a 20 33 f0 jsr $f033 jsr _x2 +.f01d 68 pla pla + + ; Add the decimal digit in A. +.f01e 85 ca sta $ca sta far_addr+2 +.f020 64 cb stz $cb stz far_addr+3 +.f022 20 3e f0 jsr $f03e jsr _add + + ; Zero the upper bits +.f025 64 ca stz $ca stz far_addr+2 +.f027 64 cb stz $cb stz far_addr+3 +.f029 60 rts rts + +.f02a _copy +.f02a a5 c8 lda $c8 lda far_addr+0 +.f02c 85 ca sta $ca sta far_addr+2 +.f02e a5 c9 lda $c9 lda far_addr+1 +.f030 85 cb sta $cb sta far_addr+3 +.f032 60 rts rts +.f033 _x2 +.f033 a5 c8 lda $c8 lda far_addr+0 +.f035 0a asl a asl a +.f036 85 c8 sta $c8 sta far_addr+0 +.f038 a5 c9 lda $c9 lda far_addr+1 +.f03a 2a rol a rol a +.f03b 85 c9 sta $c9 sta far_addr+1 +.f03d 60 rts rts +.f03e _add +.f03e 18 clc clc +.f03f a5 c8 lda $c8 lda far_addr+0 +.f041 65 ca adc $ca adc far_addr+2 +.f043 85 c8 sta $c8 sta far_addr+0 +.f045 a5 c9 lda $c9 lda far_addr+1 +.f047 65 cb adc $cb adc far_addr+3 +.f049 85 c9 sta $c9 sta far_addr+1 +.f04b 60 rts rts + + +.f04c load_pgx + + ; IN: File name set using SETNAM + ; + ; OUT: X/Y = end address, or carry set and A = iec error. + +.f04c a9 00 lda #$00 lda #0 ; Logical device # ... not meaningful here. +.f04e a6 c7 ldx $c7 ldx device +.f050 a0 00 ldy #$00 ldy #0 ; Not used +.f052 20 ba ff jsr $ffba jsr SETLFS + + ; Reset the iec queue and status +.f055 20 f5 e7 jsr $e7f5 jsr kernel.iec.reset + + ; Open the file for read. + ; NOTE: returns a KERNAL error; must check READST as well! +.f058 20 80 e8 jsr $e880 jsr kernel.iec.open_file_for_read +.f05b b0 19 bcs $f076 bcs _out +.f05d 20 b7 ff jsr $ffb7 jsr READST +.f060 09 00 ora #$00 ora #0 +.f062 d0 13 bne $f077 bne _error + + ; Read the file, sets X/Y to last address. +.f064 20 7d f0 jsr $f07d jsr read_pgx_data +.f067 90 08 bcc $f071 bcc _close + + ; Try to close the file while preserving the original error. +.f069 48 pha pha +.f06a 20 d2 e8 jsr $e8d2 jsr kernel.iec.close_file +.f06d 68 pla pla +.f06e 38 sec sec +.f06f 80 06 bra $f077 bra _error +.f071 _close +.f071 20 d2 e8 jsr $e8d2 jsr kernel.iec.close_file +.f074 b0 01 bcs $f077 bcs _error + +.f076 60 rts _out rts +.f077 _error +.f077 20 28 e7 jsr $e728 jsr error +.f07a 18 clc clc +.f07b 80 f9 bra $f076 bra _out + + +.f07d read_pgx_data + + ; Internal funciton. + ; Implements load-body for .pgx files. + ; + ; IN: SETNAM and SETLFS have been called. + ; + ; Out: X:Y = end address, far_addr = exec address + ; On error, Carry set, and A = IEC error (READST value) + + ; Make sure it's a PGX file. +.f07d a2 00 ldx #$00 ldx #0 +.f07f 20 a5 ff jsr $ffa5 _signature jsr IECIN +.f082 b0 23 bcs $f0a7 bcs _error +.f084 dd ba f0 cmp $f0ba,x cmp _ident,x +.f087 d0 35 bne $f0be bne _mismatch +.f089 e8 inx inx +.f08a e0 04 cpx #$04 cpx #4 +.f08c d0 f1 bne $f07f bne _signature + + ; Read the dest and exec addresses. +.f08e a2 00 ldx #$00 ldx #0 +.f090 20 a5 ff jsr $ffa5 _addr jsr IECIN +.f093 b0 12 bcs $f0a7 bcs _error +.f095 95 cc sta $cc,x sta far_dest,x +.f097 95 c8 sta $c8,x sta far_addr,x +.f099 e8 inx inx +.f09a e0 04 cpx #$04 cpx #4 +.f09c d0 f2 bne $f090 bne _addr + +.f09e _loop +.f09e 20 a5 ff jsr $ffa5 jsr IECIN +.f0a1 90 07 bcc $f0aa bcc _found +.f0a3 49 40 eor #$40 eor #kernel.iec.EOI +.f0a5 f0 0d beq $f0b4 beq _done +.f0a7 4c 28 e7 jmp $e728 _error jmp error ; Forward the IEC error status. + +.f0aa _found +.f0aa 20 6f f2 jsr $f26f jsr platform.far_store +.f0ad a2 cc ldx #$cc ldx #far_dest +.f0af 20 c3 f0 jsr $f0c3 jsr far_inc + +.f0b2 90 ea bcc $f09e bcc _loop +.f0b4 18 clc _done clc +.f0b5 _out +.f0b5 a6 cc ldx $cc ldx far_dest+0 +.f0b7 a4 cd ldy $cd ldy far_dest+1 +.f0b9 60 rts rts + +>f0ba 50 47 58 00 _ident .text "PGX",0 ; 6502 family +.f0be a9 10 lda #$10 _mismatch lda #kernel.iec.MISMATCH +.f0c0 38 sec sec +.f0c1 80 e4 bra $f0a7 bra _error + + +.f0c3 far_inc + ; IN: X->32 bit long in DP +.f0c3 f6 00 inc $00,x inc 0,x +.f0c5 d0 0a bne $f0d1 bne _done +.f0c7 f6 01 inc $01,x inc 1,x +.f0c9 d0 06 bne $f0d1 bne _done +.f0cb f6 02 inc $02,x inc 2,x +.f0cd d0 02 bne $f0d1 bne _done +.f0cf f6 03 inc $03,x inc 3,x +.f0d1 60 rts _done rts + + +.f0d2 load_pgz ; TODO: share this code with pgx + + ; IN: File name set using SETNAM + ; + ; OUT: X/Y = end address, or carry set and A = iec error. + +.f0d2 a9 00 lda #$00 lda #0 ; Logical device # ... not meaningful here. +.f0d4 a6 c7 ldx $c7 ldx device +.f0d6 a0 00 ldy #$00 ldy #0 ; Not used +.f0d8 20 ba ff jsr $ffba jsr SETLFS + + ; Reset the iec queue and status +.f0db 20 f5 e7 jsr $e7f5 jsr kernel.iec.reset + + ; Open the file for read. + ; NOTE: returns a KERNAL error; must check READST as well! +.f0de 20 80 e8 jsr $e880 jsr kernel.iec.open_file_for_read +.f0e1 b0 19 bcs $f0fc bcs _out +.f0e3 20 b7 ff jsr $ffb7 jsr READST +.f0e6 09 00 ora #$00 ora #0 +.f0e8 d0 13 bne $f0fd bne _error + + ; Read the file, sets X/Y to last address. +.f0ea 20 03 f1 jsr $f103 jsr read_pgz_data +.f0ed 90 08 bcc $f0f7 bcc _close + + ; Try to close the file while preserving the original error. +.f0ef 48 pha pha +.f0f0 20 d2 e8 jsr $e8d2 jsr kernel.iec.close_file +.f0f3 68 pla pla +.f0f4 38 sec sec +.f0f5 80 06 bra $f0fd bra _error +.f0f7 _close +.f0f7 20 d2 e8 jsr $e8d2 jsr kernel.iec.close_file +.f0fa b0 01 bcs $f0fd bcs _error + +.f0fc 60 rts _out rts +.f0fd _error +.f0fd 20 28 e7 jsr $e728 jsr error +.f100 18 clc clc +.f101 80 f9 bra $f0fc bra _out + + +.f103 read_pgz_data + +.f103 a9 02 lda #$02 lda #2 +.f105 85 01 sta $01 sta $1 + + ; Internal funciton. + ; Implements load-body for .pgz files. + ; + ; IN: SETNAM and SETLFS have been called. + ; + ; Out: X:Y = end address, far_addr = exec address + ; On error, Carry set, and A = IEC error (READST value) + +.f107 20 a5 ff jsr $ffa5 jsr IECIN +.f10a b0 65 bcs $f171 bcs _error +.f10c c9 5a cmp #$5a cmp #'Z' +.f10e f0 0a beq $f11a beq _pgz24 +.f110 c9 7a cmp #$7a cmp #'z' +.f112 f0 0c beq $f120 beq _pgz32 +.f114 a9 10 lda #$10 _mismatch lda #kernel.iec.MISMATCH +.f116 38 sec sec +.f117 4c 71 f1 jmp $f171 jmp _error + +.f11a a9 03 lda #$03 _pgz24 lda #3 +.f11c 85 d4 sta $d4 sta addr_len +.f11e 80 06 bra $f126 bra _read + +.f120 a9 04 lda #$04 _pgz32 lda #4 +.f122 85 d4 sta $d4 sta addr_len +.f124 80 00 bra $f126 bra _read + +.f126 _read +.f126 a2 00 ldx #$00 ldx #0 +.f128 _zero +.f128 74 c8 stz $c8,x stz far_addr,x +.f12a 74 cc stz $cc,x stz far_dest,x +.f12c 74 d0 stz $d0,x stz far_count,x +.f12e e8 inx inx +.f12f e0 04 cpx #$04 cpx #4 +.f131 d0 f5 bne $f128 bne _zero + +.f133 _block + ; Read the dest address. +.f133 a2 00 ldx #$00 ldx #0 +.f135 20 a5 ff jsr $ffa5 jsr IECIN +.f138 b0 4f bcs $f189 bcs _end +.f13a 80 05 bra $f141 bra _next +.f13c 20 a5 ff jsr $ffa5 _dest jsr IECIN +.f13f b0 30 bcs $f171 bcs _error +.f141 95 cc sta $cc,x _next sta far_dest,x +.f143 e8 inx inx +.f144 e4 d4 cpx $d4 cpx addr_len +.f146 d0 f4 bne $f13c bne _dest + + ; Read the byte count into far_count +.f148 a2 00 ldx #$00 ldx #0 +.f14a 20 a5 ff jsr $ffa5 _count jsr IECIN +.f14d b0 22 bcs $f171 bcs _error +.f14f 95 d0 sta $d0,x sta far_count,x +.f151 e8 inx inx +.f152 e4 d4 cpx $d4 cpx addr_len +.f154 d0 f4 bne $f14a bne _count + + ; See if this is an empty block (start addr) +.f156 20 a1 f1 jsr $f1a1 jsr test_far_count +.f159 d0 0d bne $f168 bne _loop ; Nope, read in the data + + ; Empty block implies the block address is the start address +.f15b a2 00 ldx #$00 ldx #0 +.f15d b5 cc lda $cc,x _copy lda far_dest,x +.f15f 95 c8 sta $c8,x sta far_addr,x +.f161 e8 inx inx +.f162 e4 d4 cpx $d4 cpx addr_len +.f164 d0 f7 bne $f15d bne _copy + +.f166 80 cb bra $f133 bra _block + +.f168 _loop +.f168 20 a5 ff jsr $ffa5 jsr IECIN +.f16b 90 07 bcc $f174 bcc _found +.f16d 49 40 eor #$40 eor #kernel.iec.EOI +.f16f f0 a3 beq $f114 beq _mismatch +.f171 4c 28 e7 jmp $e728 _error jmp error ; Forward the IEC error status. + +.f174 _found + ;ldx far_dest + ;sta $c000,x +.f174 8d 4f c0 sta $c04f sta $c000+79 +.f177 20 6f f2 jsr $f26f jsr platform.far_store +.f17a a2 cc ldx #$cc ldx #far_dest +.f17c 20 c3 f0 jsr $f0c3 jsr far_inc +.f17f 20 8f f1 jsr $f18f jsr dec_far_count +.f182 20 a1 f1 jsr $f1a1 jsr test_far_count +.f185 d0 e1 bne $f168 bne _loop +.f187 80 aa bra $f133 bra _block + +.f189 _end +.f189 49 40 eor #$40 eor #kernel.iec.EOI +.f18b d0 e4 bne $f171 bne _error +.f18d 18 clc clc +.f18e 60 rts rts + + +.f18f dec_far_count +.f18f 18 clc clc ; Subtracting one. +.f190 a2 00 ldx #$00 ldx #0 +.f192 b5 d0 lda $d0,x _loop lda far_count,x +.f194 e9 00 sbc #$00 sbc #0 +.f196 95 d0 sta $d0,x sta far_count,x +.f198 b0 05 bcs $f19f bcs _done +.f19a e8 inx inx +.f19b e0 04 cpx #$04 cpx #4 +.f19d d0 f3 bne $f192 bne _loop +.f19f 18 clc _done clc +.f1a0 60 rts rts + +.f1a1 test_far_count +.f1a1 a5 d0 lda $d0 lda far_count+0 +.f1a3 05 d1 ora $d1 ora far_count+1 +.f1a5 05 d2 ora $d2 ora far_count+2 +.f1a7 05 d3 ora $d3 ora far_count+3 +.f1a9 60 rts rts + + .send + .endn + .endn + + + +;****** Processing input file: platform/jr/jr.asm + + ; OpenKERNAL - a clean-room implementation of the C64's KERNAL ABI. + ; Copyright 2022 Jessie Oberreuter . + ; SPDX-License-Identifier: GPL-3.0-only + + ; Startup for OpenKERNAL on the C256 Foenix Jr. + + .cpu "w65c02" + + * = $fff6 ; Keep the Jr's CPU busy during code upload. +.fff6 4c f6 ff jmp $fff6 wreset jmp wreset + + * = $fffa ; Hardware vectors. +>fffa 4f f2 .word platform.hw_nmi +>fffc ab f1 .word platform.hw_reset +>fffe 53 f2 .word platform.hw_irq + + platform .namespace + + .section dp +>00d5 mmuctl .byte ? ; Holds $0 during interrupt processing. +>00d6 iomap .byte ? ; Holds $1 during interrupt processing. +>00d7 ptr .word ? ; for far_write +>00d9 tmp .byte ? ; for far_write + .send + + .section kmem +>0399 nmi_flag .byte ? + .send + + spin .macro OFFSET + .endm + + .section kernel + +>f1aa 00 booted .byte 0 ; Reset detect; overwritten by a code push. + +.f1ab hw_reset: + +.f1ab 78 sei sei + + ; Initialize the stack pointer +.f1ac a2 ff ldx #$ff ldx #$ff +.f1ae 9a txs txs + + ; "clear" the NMI flag. +.f1af ba tsx tsx +.f1b0 8e 99 03 stx $0399 stx nmi_flag + + ; Check for a reset after the kernel has started. +.f1b3 ad aa f1 lda $f1aa lda booted +.f1b6 d0 17 bne $f1cf bne upload ; Enter "wait for upload" mode. +.f1b8 ee aa f1 inc $f1aa inc booted + + ; Set up MMU LUTs +.f1bb 20 f0 f1 jsr $f1f0 jsr mmu_init + + ; Initialize the hardware +.f1be 20 16 f2 jsr $f216 jsr init +.f1c1 b0 09 bcs $f1cc bcs _error + + ; Default $c000 to general I/O. +.f1c3 64 01 stz $01 stz $1 + + ; Switch to MMU 3 and chain to the kernel. +.f1c5 a9 33 lda #$33 lda #%00110011 ; LUT3 mapped and pre-set for edit. +.f1c7 85 00 sta $00 sta $0 +.f1c9 4c 5d e7 jmp $e75d jmp kernel.start +.f1cc 4c 28 e7 jmp $e728 _error jmp kernel.error + +.f1cf upload: ; TODO: use kernel string service +.f1cf 20 e4 f7 jsr $f7e4 jsr console.init +.f1d2 a9 e9 lda #$e9 lda #<_msg +.f1d4 85 a5 sta $a5 sta kernel.src +.f1d6 a9 f1 lda #$f1 lda #>_msg +.f1d8 85 a6 sta $a6 sta kernel.src+1 +.f1da a0 00 ldy #$00 ldy #0 +.f1dc b1 a5 lda ($a5),y _loop lda (kernel.src),y +.f1de f0 06 beq $f1e6 beq _done +.f1e0 20 b9 f9 jsr $f9b9 jsr console.putc +.f1e3 c8 iny iny +.f1e4 80 f6 bra $f1dc bra _loop +.f1e6 4c f6 ff jmp $fff6 _done jmp wreset +>f1e9 55 70 6c 6f 61 64 00 _msg .null "Upload" + + +.f1f0 mmu_init + + ; Set up MMU LUTs 1-3 to match MMU0 while interrupts are off. +.f1f0 a9 80 lda #$80 lda #%10000000 ; Edit MMU 0 (MMU0 mapped) +.f1f2 20 07 f2 jsr $f207 jsr _fill +.f1f5 a9 90 lda #$90 lda #%10010000 ; Edit MMU 1 (MMU0 mapped) +.f1f7 20 07 f2 jsr $f207 jsr _fill +.f1fa a9 a0 lda #$a0 lda #%10100000 ; Edit MMU 2 (MMU0 mapped) +.f1fc 20 07 f2 jsr $f207 jsr _fill +.f1ff a9 b0 lda #$b0 lda #%10110000 ; Edit MMU 3 (MMU0 mapped) +.f201 20 07 f2 jsr $f207 jsr _fill + +.f204 64 00 stz $00 stz $0 ; Return MMU0, no LUT mapped. +.f206 60 rts rts +.f207 _fill +.f207 85 00 sta $00 sta $0 +.f209 a2 00 ldx #$00 ldx #0 +.f20b _loop +.f20b 8a txa txa +.f20c 95 08 sta $08,x sta $8,x +.f20e 95 10 sta $10,x sta $10,x +.f210 e8 inx inx +.f211 e0 08 cpx #$08 cpx #8 +.f213 d0 f6 bne $f20b bne _loop + +.f215 60 rts rts + +.f216 init +.f216 20 d9 f2 jsr $f2d9 jsr INIT_CODEC +.f219 20 00 f5 jsr $f500 jsr irq.init +.f21c 20 fa e6 jsr $e6fa jsr kernel.init +.f21f 20 e4 f7 jsr $f7e4 jsr console.init +.f222 b0 0a bcs $f22e bcs _out + +.f224 64 01 stz $01 stz $1 +.f226 20 2f f2 jsr $f22f jsr tick_init +.f229 20 b8 f7 jsr $f7b8 jsr ps2.init +.f22c b0 00 bcs $f22e bcs _out + +.f22e 60 rts _out rts + + +.f22f tick_init + ; TODO: allocate the device handle. + +.f22f 20 1a fb jsr $fb1a jsr c64kbd.init + +.f232 a9 49 lda #$49 lda #tick +.f239 8d 01 04 sta $0401 sta frame+1 + +.f23c a9 00 lda #$00 lda #. + ; SPDX-License-Identifier: GPL-3.0-only + + .cpu "w65c02" + + .namespace platform + iec .namespace + + ; The C256 Foenix Jr. has the low-level IEC protocol implemented in its FPGA. + + ; IEC + + ; Writting: +=$d680 TALKER_CMD = $D680 ; Write all Command here, save $3F, $5F +=$d681 TALKER_CMD_LAST = $D681 ; This is for $3F or $5F Only +=$d682 TALKER_DTA = $D682 ; Any other data, write here +=$d683 TALKER_DTA_LAST = $D683 ; Write to this address for the last data to send + + ; Reading: +=$d680 LISTNER_DTA = $D680 ; Read Data From FIFO +=$d681 LISTNER_FIFO_STAT = $D681 ; Bit[0] Empty Flag (1 = Empty, 0 = Data in FIFO) +=$d682 LISTNER_FIFO_CNT_LO = $D682 +=$d683 LISTNER_FIFO_CNT_HI = $D683 + +=1 STAT_RX_NEMPTY = 1 +=2 STAT_RX_FULL = 2 +=4 STAT_RX_EOI = 4 +=16 STAT_NO_ACK = 16 ; Device not preset + + .section dp +>00da iec_timeout .byte ? +>00db mark .byte ? +>00dc eoi .byte ? + .send + + .section kernel + +.f38a settmo +.f38a 85 da sta $da sta iec_timeout +.f38c 60 rts rts + +.f38d read_byte + + ; Return EOI if the stream has hit EOI. +.f38d a5 dc lda $dc lda eoi +.f38f f0 04 beq $f395 beq _read +.f391 a9 40 lda #$40 lda #kernel.iec.EOI +.f393 38 sec sec +.f394 60 rts rts + +.f395 _read + ; Save I/O map and switch to I/O Zero. +.f395 da phx phx +.f396 a6 01 ldx $01 ldx $1 +.f398 64 01 stz $01 stz $1 + +.f39a 97 01 smb 1,$01 smb 1,$1 +.f39c ee 4f c0 inc $c04f inc $c000+79 +.f39f 64 01 stz $01 stz $1 + + ; Set 'mark' to the future timeout time. + ; The C64 claims to time out after 64ms. + ; To be safe (not knowing where we are + ; in the current "tick" cycle), we wait + ; ~0.066 - ~0.08s. +.f3a1 a5 a3 lda $a3 lda kernel.ticks +.f3a3 18 clc clc +.f3a4 69 05 adc #$05 adc #5 ; 4=0.66s + 1 +.f3a6 85 db sta $db sta mark +.f3a8 _loop +.f3a8 ad 81 d6 lda $d681 lda LISTNER_FIFO_STAT +.f3ab 4a lsr a lsr a ; Carry set if fifo is empty +.f3ac 90 0c bcc $f3ba bcc _found + + ; If timeouts are disabled, just keep trying... +.f3ae a5 da lda $da lda iec_timeout + ;bpl _loop ; no timeout check + + ; Otherwise, keep trying until we reach mark. +.f3b0 a5 a3 lda $a3 lda kernel.ticks +.f3b2 c5 db cmp $db cmp mark +.f3b4 90 f2 bcc $f3a8 bcc _loop + + ; Report a timeout; carry is already set. +.f3b6 a5 02 lda $02 lda kernel.iec.TIMEOUT_READ +.f3b8 80 0c bra $f3c6 bra _out + +.f3ba _found + ; Read the data. +.f3ba ad 80 d6 lda $d680 lda LISTNER_DTA + + ; Update our internal EOI flag. +.f3bd 48 pha pha +.f3be ad 81 d6 lda $d681 lda LISTNER_FIFO_STAT +.f3c1 29 04 and #$04 and #STAT_RX_EOI +.f3c3 85 dc sta $dc sta eoi +.f3c5 68 pla pla + +.f3c6 _out + ; Restore I/O map. +.f3c6 86 01 stx $01 stx $1 +.f3c8 fa plx plx +.f3c9 60 rts rts + + +.f3ca write_byte +.f3ca da phx phx +.f3cb a6 01 ldx $01 ldx $1 +.f3cd 64 01 stz $01 stz $1 +.f3cf 8d 82 d6 sta $d682 sta TALKER_DTA +.f3d2 80 27 bra $f3fb bra ret_stat + +.f3d4 write_last_byte +.f3d4 da phx phx +.f3d5 a6 01 ldx $01 ldx $1 +.f3d7 64 01 stz $01 stz $1 +.f3d9 8d 83 d6 sta $d683 sta TALKER_DTA_LAST +.f3dc 80 1d bra $f3fb bra ret_stat + +.f3de send_atn_byte +.f3de 97 01 smb 1,$01 smb 1,$1 +.f3e0 17 01 rmb 1,$01 rmb 1,$1 +.f3e2 ee 4e c0 inc $c04e inc $c000+78 +.f3e5 64 01 stz $01 stz $1 +.f3e7 da phx phx +.f3e8 a6 01 ldx $01 ldx $1 +.f3ea 64 01 stz $01 stz $1 +.f3ec 8d 80 d6 sta $d680 sta TALKER_CMD +.f3ef 80 0a bra $f3fb bra ret_stat + +.f3f1 send_atn_last_byte +.f3f1 da phx phx +.f3f2 a6 01 ldx $01 ldx $1 +.f3f4 64 01 stz $01 stz $1 +.f3f6 8d 81 d6 sta $d681 sta TALKER_CMD_LAST +.f3f9 80 00 bra $f3fb bra ret_stat + +.f3fb ret_stat +.f3fb 64 dc stz $dc stz eoi +.f3fd 20 0f f4 jsr $f40f jsr delay500us ; Better would be wait for empty tx fifo or timeout. +.f400 ad 81 d6 lda $d681 lda LISTNER_FIFO_STAT +.f403 29 10 and #$10 and #STAT_NO_ACK +.f405 18 clc clc +.f406 f0 03 beq $f40b beq _out +.f408 38 sec sec +.f409 a9 80 lda #$80 lda #kernel.iec.NO_DEVICE ; TODO: when is this set? +.f40b _out +.f40b 86 01 stx $01 stx $1 +.f40d fa plx plx +.f40e 60 rts rts + +.f40f delay500us +.f40f a9 32 lda #$32 lda #50 ; Kill ~500us +.f411 20 17 f4 jsr $f417 _loop jsr _delay10us +.f414 3a dec a dec a +.f415 d0 fa bne $f411 bne _loop + +.f417 20 20 f4 jsr $f420 _delay10us jsr _delay2 +.f41a 20 1d f4 jsr $f41d _delay8 jsr _delay4 +.f41d 20 20 f4 jsr $f420 _delay4 jsr _delay2 +.f420 20 23 f4 jsr $f423 _delay2 jsr _delay1 +.f423 _delay1 ; Kill 8 clock cycles ... slightly larger than 1Mhz = 1us +.f423 ea nop nop +.f424 ea nop nop +.f425 ea nop nop +.f426 ea nop nop +.f427 ea nop nop +.f428 60 rts rts + + .send + .endn + .endn + + +;****** Processing input file: platform/jr/irq.asm + + ; OpenKERNAL - a clean-room implementation of the C64's KERNAL ABI. + ; Copyright 2022 Jessie Oberreuter . + ; SPDX-License-Identifier: GPL-3.0-only + + ; This file is from the w6502c TinyCore kernel by the same author. + + .cpu "w65c02" + + irq .namespace + + ; Interrupt Sources + .virtual 0 +>0000 frame .byte ? +>0001 line .byte ? +>0002 ps2_0 .byte ? +>0003 ps2_1 .byte ? +>0004 timer0 .byte ? +>0005 timer1 .byte ? +>0006 dma .byte ? +>0007 .byte ? +>0008 serial .byte ? +>0009 col0 .byte ? +>000a col1 .byte ? +>000b col2 .byte ? +>000c rtc .byte ? +>000d via .byte ? +>000e iec .byte ? +>000f sdc .byte ? +.0010 max .endv + + ; Dispatch table + .section kmem +>039a irq0 .fill 8 +>03a2 irq1 .fill 8 + .send + + ; Interrupt priotity table + .section tables +>e500 00 00 01 00 02 00 01 00 first_bit: .byte 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 +>e508 03 00 01 00 02 00 01 00 +>e510 04 00 01 00 02 00 01 00 .byte 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 +>e518 03 00 01 00 02 00 01 00 +>e520 05 00 01 00 02 00 01 00 .byte 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 +>e528 03 00 01 00 02 00 01 00 +>e530 04 00 01 00 02 00 01 00 .byte 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 +>e538 03 00 01 00 02 00 01 00 +>e540 06 00 01 00 02 00 01 00 .byte 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 +>e548 03 00 01 00 02 00 01 00 +>e550 04 00 01 00 02 00 01 00 .byte 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 +>e558 03 00 01 00 02 00 01 00 +>e560 05 00 01 00 02 00 01 00 .byte 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 +>e568 03 00 01 00 02 00 01 00 +>e570 04 00 01 00 02 00 01 00 .byte 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 +>e578 03 00 01 00 02 00 01 00 +>e580 07 00 01 00 02 00 01 00 .byte 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 +>e588 03 00 01 00 02 00 01 00 +>e590 04 00 01 00 02 00 01 00 .byte 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 +>e598 03 00 01 00 02 00 01 00 +>e5a0 05 00 01 00 02 00 01 00 .byte 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 +>e5a8 03 00 01 00 02 00 01 00 +>e5b0 04 00 01 00 02 00 01 00 .byte 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 +>e5b8 03 00 01 00 02 00 01 00 +>e5c0 06 00 01 00 02 00 01 00 .byte 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 +>e5c8 03 00 01 00 02 00 01 00 +>e5d0 04 00 01 00 02 00 01 00 .byte 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 +>e5d8 03 00 01 00 02 00 01 00 +>e5e0 05 00 01 00 02 00 01 00 .byte 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 +>e5e8 03 00 01 00 02 00 01 00 +>e5f0 04 00 01 00 02 00 01 00 .byte 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 +>e5f8 03 00 01 00 02 00 01 00 + .send + + .section kernel +>f429 .align 256 +.f500 init: +.f500 48 pha pha + +.f501 64 01 stz $01 stz $1 + + ; Begin with all interrupts masked. + ; Begin with all interrupts on the falling edge. +.f503 a9 ff lda #$ff lda #$ff +.f505 8d 6c d6 sta $d66c sta INT_MASK_REG0 +.f508 8d 6d d6 sta $d66d sta INT_MASK_REG1 +.f50b 8d 68 d6 sta $d668 sta INT_EDGE_REG0 +.f50e 8d 69 d6 sta $d669 sta INT_EDGE_REG1 +.f511 ad 60 d6 lda $d660 lda INT_PENDING_REG0 +.f514 8d 60 d6 sta $d660 sta INT_PENDING_REG0 +.f517 ad 61 d6 lda $d661 lda INT_PENDING_REG1 +.f51a 8d 61 d6 sta $d661 sta INT_PENDING_REG1 + + ; Polarities aren't presently initialized in the + ; official Foenix kernel; leaving them uninitialized + ; here. + ; lda #0 + ; sta INT_POL_REG0 + ; sta INT_POL_REG2 + +.f51d a9 36 lda #$36 lda #dummy +.f524 8d 03 04 sta $0403 sta Devices+3 +.f527 a9 02 lda #$02 lda #2 +.f529 a0 00 ldy #$00 ldy #0 +.f52b 99 9a 03 sta $039a,y _loop sta irq0,y +.f52e c8 iny iny +.f52f c0 10 cpy #$10 cpy #16 +.f531 d0 f8 bne $f52b bne _loop + +.f533 58 cli cli +.f534 68 pla pla +.f535 18 clc clc +.f536 60 rts dummy rts + +.f537 show +.f537 a0 02 ldy #$02 ldy #2 +.f539 84 01 sty $01 sty $1 +.f53b 48 pha pha +.f53c 4a lsr a lsr a +.f53d 4a lsr a lsr a +.f53e 4a lsr a lsr a +.f53f 4a lsr a lsr a +.f540 a8 tay tay +.f541 b9 54 f5 lda $f554,y lda _hex,y +.f544 8d 20 c0 sta $c020 sta $c020 +.f547 68 pla pla +.f548 29 0f and #$0f and #$0f +.f54a a8 tay tay +.f54b b9 54 f5 lda $f554,y lda _hex,y +.f54e 8d 21 c0 sta $c021 sta $c021 +.f551 64 01 stz $01 stz $1 +.f553 60 rts rts +>f554 30 31 32 33 34 35 36 37 _hex .null "0123456789abcdef" +>f55c 38 39 61 62 63 64 65 66 00 +.f565 show2 +.f565 48 pha pha +.f566 5a phy phy +.f567 a0 02 ldy #$02 ldy #2 +.f569 84 01 sty $01 sty $1 +.f56b 48 pha pha +.f56c 4a lsr a lsr a +.f56d 4a lsr a lsr a +.f56e 4a lsr a lsr a +.f56f 4a lsr a lsr a +.f570 a8 tay tay +.f571 b9 86 f5 lda $f586,y lda _hex,y +.f574 8d 22 c0 sta $c022 sta $c022 +.f577 68 pla pla +.f578 29 0f and #$0f and #$0f +.f57a a8 tay tay +.f57b b9 86 f5 lda $f586,y lda _hex,y +.f57e 8d 23 c0 sta $c023 sta $c023 +.f581 64 01 stz $01 stz $1 +.f583 7a ply ply +.f584 68 pla pla +.f585 60 rts rts +>f586 30 31 32 33 34 35 36 37 _hex .null "0123456789abcdef" +>f58e 38 39 61 62 63 64 65 66 00 + +.f597 dispatch: + +.f597 64 01 stz $01 _reg0 stz $1 +.f599 ae 60 d6 ldx $d660 ldx INT_PENDING_REG0 +.f59c f0 11 beq $f5af beq _reg1 +.f59e bc 00 e5 ldy $e500,x ldy first_bit,x ; 0..7 +.f5a1 b9 c8 f5 lda $f5c8,y lda bit,y ; 1, 2, 4, ... +.f5a4 8d 60 d6 sta $d660 sta INT_PENDING_REG0 +.f5a7 be 9a 03 ldx $039a,y ldx irq0,y +.f5aa 20 00 ed jsr $ed00 jsr kernel.device.data +.f5ad 80 e8 bra $f597 bra _reg0 + +.f5af 64 01 stz $01 _reg1 stz $1 +.f5b1 ae 61 d6 ldx $d661 ldx INT_PENDING_REG1 +.f5b4 f0 11 beq $f5c7 beq _reg2 +.f5b6 bc 00 e5 ldy $e500,x ldy first_bit,b,x +.f5b9 b9 c8 f5 lda $f5c8,y lda bit,b,y +.f5bc 8d 61 d6 sta $d661 sta INT_PENDING_REG1 +.f5bf be a2 03 ldx $03a2,y ldx irq1,y +.f5c2 20 00 ed jsr $ed00 jsr kernel.device.data +.f5c5 80 e8 bra $f5af bra _reg1 + +.f5c7 60 rts _reg2 rts + +>f5c8 01 02 04 08 10 20 40 80 bit: .byte 1,2,4,8,16,32,64,128 + +.f5d0 install: + ; IN: A -> lsb of a vector in Devices + ; Y -> requested IRQ ID + +.f5d0 c0 10 cpy #$10 cpy #max +.f5d2 b0 03 bcs $f5d7 bcs _out + +.f5d4 99 9a 03 sta $039a,y sta irq0,y +.f5d7 60 rts _out rts + + +.f5d8 enable: + ; IN: A -> requested IRQ ID to enable. + +.f5d8 c9 10 cmp #$10 cmp #max +.f5da b0 0d bcs $f5e9 bcs _out + +.f5dc da phx phx +.f5dd 20 ea f5 jsr $f5ea jsr map +.f5e0 49 ff eor #$ff eor #255 ; clear bit to enable source. +.f5e2 3d 6c d6 and $d66c,x and INT_MASK_REG0,x +.f5e5 9d 6c d6 sta $d66c,x sta INT_MASK_REG0,x +.f5e8 fa plx plx + +.f5e9 60 rts _out rts + +.f5ea map: + ; A = IRQ # + ; X <- IRQth byte + ; A <- IRQth bit set + + ; Offset X to the IRQth byte. +.f5ea a2 00 ldx #$00 ldx #0 +.f5ec 89 08 bit #$08 bit #8 +.f5ee f0 01 beq $f5f1 beq _bit +.f5f0 e8 inx inx + +.f5f1 29 07 and #$07 _bit and #7 +.f5f3 5a phy phy +.f5f4 a8 tay tay +.f5f5 b9 c8 f5 lda $f5c8,y lda bit,y +.f5f8 7a ply ply +.f5f9 60 rts rts + +.f5fa disable: + ; IN: A -> requested IRQ ID to diable. + +.f5fa c9 10 cmp #$10 cmp #max +.f5fc b0 0b bcs $f609 bcs _out + +.f5fe da phx phx +.f5ff 20 ea f5 jsr $f5ea jsr map +.f602 1d 6c d6 ora $d66c,x ora INT_MASK_REG0,x +.f605 9d 6c d6 sta $d66c,x sta INT_MASK_REG0,x +.f608 fa plx plx + +.f609 60 rts _out rts + + + .send + .endn + + +;****** Processing input file: platform/jr/ps2.asm + + ; OpenKERNAL - a clean-room implementation of the C64's KERNAL ABI. + ; Copyright 2022 Jessie Oberreuter . + ; SPDX-License-Identifier: GPL-3.0-only + + ; Instantiate an i8042 PS2 stack. + + .cpu "w65c02" + + .namespace platform + ps2 .namespace + + .section kernel + +.f60a i8042 + +=$d640 BASE = $D640 + + self .namespace + .virtual DevState +>0500 queue .word ? ; write queue, must be first +>0502 qstate .word ? ; atomic queue count for irq management +>0504 lower .byte ? ; Lower handler +>0505 config .byte ? ; Current i8042 config +>0506 last .byte ? ; tick at time of last data write +>0507 mask .byte ? ; bit to check for ready status +>0508 mark .byte ? ; ticks at start of status wait loop +>0509 pending .byte ? ; true if 'data' contains pending data. +>050a data .byte ? ; delayed write while waiting for the i8042. + .endv + .endn + +=4 CMD = 4 +=0 DATA = 0 +=4 STATUS = 4 + +.f60a vectors +>f60a 52 f7 .word ps2_data +>f60c b6 f7 .word ps2_status +>f60e b6 f7 .word ps2_fetch +>f610 ee f6 .word ps2_open +>f612 99 f7 .word ps2_get +>f614 9e f7 .word ps2_set +>f616 30 f7 .word ps2_send +>f618 93 f7 .word ps2_close + +.f61a init +.f61a 20 2a ed jsr $ed2a jsr kernel.device.alloc +.f61d b0 09 bcs $f628 bcs _out +.f61f 20 29 f6 jsr $f629 jsr ps2_init +.f622 90 04 bcc $f628 bcc _out +.f624 20 3a ed jsr $ed3a jsr kernel.device.free +.f627 38 sec sec +.f628 60 rts _out rts + +.f629 ps2_init + ; 0. Disable IRQs +.f629 a9 02 lda #$02 lda #irq.ps2_0 +.f62b 20 fa f5 jsr $f5fa jsr irq.disable +.f62e a9 03 lda #$03 lda #irq.ps2_1 +.f630 20 fa f5 jsr $f5fa jsr irq.disable + + ; 1. Init the USB controllers (N/A) + ; 2. Determine if the i8042 exists (N/A) + + ; 3. Disable the ports + + ; Dispable the first port +.f633 a9 ac lda #$ac lda #$ac +.f635 20 8e f6 jsr $f68e jsr send_cmd + + ; Disable the second port +.f638 a9 a7 lda #$a7 lda #$a7 +.f63a 20 8e f6 jsr $f68e jsr send_cmd + + ; 4. Flush the recv queueu +.f63d 20 a0 f6 jsr $f6a0 jsr flush +.f640 b0 2b bcs $f66d bcs _out + + ; 5. Configure the controller +.f642 20 6e f6 jsr $f66e jsr _configure +.f645 b0 26 bcs $f66d bcs _out + + + ; 6. Test the controller +.f647 a9 aa lda #$aa lda #$aa +.f649 20 ae f6 jsr $f6ae jsr txrx +.f64c b0 1f bcs $f66d bcs _out +.f64e c9 55 cmp #$55 cmp #$55 +.f650 38 sec sec +.f651 d0 1a bne $f66d bne _out +.f653 20 6e f6 jsr $f66e jsr _configure +.f656 b0 15 bcs $f66d bcs _out + + ; 7. Enable port 2 and recheck bit 5 (N/A) + + ; 8. Test the ports (meh) + + ; 9. Set the post bit +.f658 bd 05 05 lda $0505,x lda self.config,x +.f65b 09 04 ora #$04 ora #4 +.f65d 20 7c f6 jsr $f67c jsr send_conf +.f660 b0 0b bcs $f66d bcs _out +.f662 _vectors +.f662 a9 0a lda #$0a lda #vectors +.f668 85 a6 sta $a6 sta kernel.src+1 +.f66a 20 47 ed jsr $ed47 jsr kernel.device.install + +.f66d 60 rts _out rts + +.f66e _configure +.f66e a9 20 lda #$20 lda #$20 ; CmdGetConfig +.f670 20 ae f6 jsr $f6ae jsr txrx +.f673 b0 f8 bcs $f66d bcs _out +.f675 29 bc and #$bc and #255-1-2-64 +.f677 29 0f and #$0f and #$0f +.f679 4c 7c f6 jmp $f67c jmp send_conf + +.f67c send_conf +.f67c 48 pha pha +.f67d a9 60 lda #$60 lda #$60 ; CmdSetConfig +.f67f 20 8e f6 jsr $f68e jsr send_cmd +.f682 68 pla pla +.f683 b0 08 bcs $f68d bcs _end +.f685 20 97 f6 jsr $f697 jsr send_data +.f688 b0 03 bcs $f68d bcs _end +.f68a 9d 05 05 sta $0505,x sta self.config,b,x +.f68d 60 rts _end rts + + +.f68e send_cmd: +.f68e 20 c1 f6 jsr $f6c1 jsr tx_wait +.f691 b0 03 bcs $f696 bcs _out +.f693 8d 44 d6 sta $d644 sta BASE+CMD +.f696 60 rts _out rts + +.f697 send_data: +.f697 20 c1 f6 jsr $f6c1 jsr tx_wait +.f69a b0 03 bcs $f69f bcs _out +.f69c 8d 40 d6 sta $d640 sta BASE+DATA +.f69f 60 rts _out rts + +.f6a0 a0 64 ldy #$64 flush ldy #100 ; Max bytes to eat. +.f6a2 20 b4 f6 jsr $f6b4 _flush jsr recv_data +.f6a5 b0 05 bcs $f6ac bcs _flushed +.f6a7 88 dey dey +.f6a8 d0 f8 bne $f6a2 bne _flush +.f6aa 38 sec sec +.f6ab 60 rts rts +.f6ac 18 clc _flushed clc +.f6ad 60 rts rts + +.f6ae txrx: +.f6ae 20 8e f6 jsr $f68e jsr send_cmd +.f6b1 90 01 bcc $f6b4 bcc recv_data +.f6b3 60 rts rts + +.f6b4 recv_data: +.f6b4 20 bd f6 jsr $f6bd jsr rx_wait +.f6b7 b0 03 bcs $f6bc bcs _out +.f6b9 ad 40 d6 lda $d640 lda BASE+DATA +.f6bc 60 rts _out rts + +.f6bd rx_wait: +.f6bd a9 01 lda #$01 lda #1 +.f6bf 80 08 bra $f6c9 bra wait + +.f6c1 tx_wait: +.f6c1 48 pha pha +.f6c2 a9 02 lda #$02 lda #2 +.f6c4 20 c9 f6 jsr $f6c9 jsr wait +.f6c7 68 pla pla +.f6c8 60 rts rts + +.f6c9 wait: + ; IN: A = bit to wait on + ; OUT: Carry set on timeout + +.f6c9 9d 07 05 sta $0507,x sta self.mask,x +.f6cc a5 a3 lda $a3 lda kernel.ticks +.f6ce 9d 08 05 sta $0508,x sta self.mark,x + +.f6d1 18 clc clc +.f6d2 ad 44 d6 lda $d644 _loop lda BASE+STATUS +.f6d5 49 02 eor #$02 eor #2 ; normalize +.f6d7 3d 07 05 and $0507,x and self.mask,x +.f6da f0 01 beq $f6dd beq _wait +.f6dc 60 rts _out rts + +.f6dd a5 a3 lda $a3 _wait lda kernel.ticks +.f6df 38 sec sec +.f6e0 fd 08 05 sbc $0508,x sbc self.mark,x +.f6e3 c9 1e cmp #$1e cmp #30 +.f6e5 b0 f5 bcs $f6dc bcs _out +.f6e7 20 f8 e6 jsr $e6f8 jsr kernel.thread.yield +.f6ea 80 e6 bra $f6d2 bra _loop + +.f6ec hang + .if false + .endif +.f6ec 80 fe bra $f6ec bra hang + +=54864 TIMER0_CTRL_REG = $d650+$0 +=54865 TIMER0_CHARGE_L = $d650+$1 +=54866 TIMER0_CHARGE_M = $d650+$2 +=54867 TIMER0_CHARGE_H = $d650+$3 +=54868 TIMER0_CMP_REG = $d650+$4 +=54869 TIMER0_CMP_L = $d650+$5 +=54870 TIMER0_CMP_M = $d650+$6 +=54871 TIMER0_CMP_H = $d650+$7 + +=$01 TMR0_EN = $01 +=$02 TMR0_SCLR = $02 +=$04 TMR0_SLOAD = $04 ; Use SLOAD is +=$08 TMR0_UPDWN = $08 + +=$01 TMR0_CMP_RECLR = $01 ; set to one for it to cycle when Counting up +=$02 TMR0_CMP_RELOAD = $02 ; Set to one for it to reload when Counting Down + + .virtual Tokens +>0200 port .byte ? +>0201 data .byte ? + .endv + + +.f6ee ps2_open + +.f6ee 20 5c ed jsr $ed5c jsr kernel.device.queue.init +.f6f1 9e 09 05 stz $0509,x stz self.pending,x + +.f6f4 a9 ff lda #$ff lda #$ff +.f6f6 9d 02 05 sta $0502,x sta self.qstate,x ; qstate == 0 when count is 1. + +.f6f9 8a txa txa +.f6fa a0 04 ldy #$04 ldy #irq.timer0 +.f6fc 20 d0 f5 jsr $f5d0 jsr irq.install + +.f6ff a9 a8 lda #$a8 lda #$a8 +.f701 8d 55 d6 sta $d655 sta TIMER0_CMP_L +.f704 a9 61 lda #$61 lda #$61 +.f706 8d 56 d6 sta $d656 sta TIMER0_CMP_M +.f709 a9 00 lda #$00 lda #$0 +.f70b 8d 57 d6 sta $d657 sta TIMER0_CMP_H + +.f70e 9c 51 d6 stz $d651 stz TIMER0_CHARGE_L +.f711 9c 52 d6 stz $d652 stz TIMER0_CHARGE_M +.f714 9c 53 d6 stz $d653 stz TIMER0_CHARGE_H + +.f717 a9 02 lda #$02 lda #TMR0_CMP_RELOAD +.f719 8d 54 d6 sta $d654 sta TIMER0_CMP_REG + +.f71c a9 64 lda #$64 lda #100 +.f71e 8d 19 d0 sta $d019 sta VKY_LINE_CMP_VALUE_LO +.f721 9c 1a d0 stz $d01a stz VKY_LINE_CMP_VALUE_HI +.f724 a9 01 lda #$01 lda #1 +.f726 8d 18 d0 sta $d018 sta VKY_LINE_IRQ_CTRL_REG + +.f729 a9 04 lda #$04 lda #irq.timer0 +.f72b 20 d8 f5 jsr $f5d8 jsr irq.enable + +.f72e 18 clc clc +.f72f 60 rts rts + + +.f730 ps2_send + ; Asynchronously send the byte in A to the device at port Y. + ; A = byte, Y = port + ; Carry set on error (no free tokens) +.f730 5a phy phy + +.f731 20 b6 ed jsr $edb6 jsr kernel.token.alloc +.f734 90 02 bcc $f738 bcc _queue +.f736 7a ply ply +.f737 60 rts rts + +.f738 _queue +.f738 99 01 02 sta $0201,y sta data,y +.f73b 68 pla pla +.f73c 99 00 02 sta $0200,y sta port,y + +.f73f 20 63 ed jsr $ed63 jsr kernel.device.queue.enque +.f742 fe 02 05 inc $0502,x inc self.qstate,x +.f745 d0 03 bne $f74a bne _ack +.f747 20 4c f7 jsr $f74c jsr timer_resume + +.f74a _ack + .if false + .endif +.f74a 18 clc clc +.f74b 60 rts rts + + +.f74c timer_resume +.f74c a9 0d lda #$0d lda #TMR0_EN | TMR0_SLOAD | TMR0_UPDWN +.f74e 8d 50 d6 sta $d650 sta TIMER0_CTRL_REG + .if false + .endif +.f751 60 rts rts + +.f752 ps2_data + ; IRQ handler for asynchronously sending bytes to PS2 devices. + + ; Verify that the i8042 can accept writes +.f752 ad 44 d6 lda $d644 lda BASE+STATUS +.f755 89 02 bit #$02 bit #2 +.f757 d0 21 bne $f77a bne _wait + + ; If we have pending data, send it now. +.f759 bd 0a 05 lda $050a,x lda self.data,x +.f75c bc 09 05 ldy $0509,x ldy self.pending,x +.f75f d0 13 bne $f774 bne _send + +.f761 20 74 ed jsr $ed74 jsr kernel.device.queue.deque +.f764 b0 17 bcs $f77d bcs _done +.f766 de 02 05 dec $0502,x dec self.qstate,x + +.f769 b9 00 02 lda $0200,y lda port,y +.f76c d0 10 bne $f77e bne _prefix + +.f76e b9 01 02 lda $0201,y lda data,y +.f771 20 cc ed jsr $edcc jsr kernel.token.free + +.f774 8d 40 d6 sta $d640 _send sta BASE+DATA +.f777 9e 09 05 stz $0509,x stz self.pending,x + .if false + .endif + +.f77a 20 4c f7 jsr $f74c _wait jsr timer_resume +.f77d 60 rts _done rts + +.f77e _prefix + + ; Send the prefix command for a write to the second port +.f77e a9 d4 lda #$d4 lda #$d4 +.f780 8d 44 d6 sta $d644 sta BASE+CMD + + ; Flag pending +.f783 9d 09 05 sta $0509,x sta self.pending,x ; force pending to non-zero (ie #$d4) + + ; Queue the data byte +.f786 b9 01 02 lda $0201,y lda data,y +.f789 9d 0a 05 sta $050a,x sta self.data,x +.f78c 20 cc ed jsr $edcc jsr kernel.token.free + +.f78f 80 e9 bra $f77a bra _wait ; The i8042 core lies... +.f791 80 bf bra $f752 bra ps2_data ; Try to send straight away (queuing i8042) + +.f793 ps2_close +.f793 a9 04 lda #$04 lda #irq.timer0 +.f795 20 fa f5 jsr $f5fa jsr irq.disable +.f798 60 rts rts + +.f799 ps2_get +.f799 ad 40 d6 lda $d640 lda BASE+DATA +.f79c 18 clc clc +.f79d 60 rts rts + +.f79e ps2_set + ; Enable (/disable) the port + ; Y = port # + + ; Enable the interrupt on the i8042 +.f79e b9 b2 f7 lda $f7b2,y lda _irq,y +.f7a1 1d 05 05 ora $0505,x ora self.config,x +.f7a4 20 7c f6 jsr $f67c jsr send_conf +.f7a7 b0 08 bcs $f7b1 bcs _out + + ; Enable the port +.f7a9 b9 b4 f7 lda $f7b4,y lda _port,y +.f7ac 20 8e f6 jsr $f68e jsr send_cmd +.f7af b0 00 bcs $f7b1 bcs _out + +.f7b1 60 rts _out rts + +>f7b2 01 02 _irq .byte $01, $02 +>f7b4 ae a8 _port .byte $ae, $a8 + + +.f7b6 ps2_status +.f7b6 ps2_fetch +.f7b6 18 clc clc +.f7b7 60 rts rts + + +.f7b8 init +.f7b8 64 01 stz $01 stz $1 ; The i8042 registers are in General I/O. + + ; Init and open the i8042 device. +.f7ba 20 1a f6 jsr $f61a jsr i8042.init +.f7bd b0 24 bcs $f7e3 bcs _out +.f7bf 20 09 ed jsr $ed09 jsr kernel.device.open +.f7c2 b0 1f bcs $f7e3 bcs _out + + ; Init and open the first PS2 device. +.f7c4 da phx phx +.f7c5 8a txa txa +.f7c6 a0 02 ldy #$02 ldy #irq.ps2_0 +.f7c8 20 3a fc jsr $fc3a jsr hardware.ps2.init +.f7cb b0 03 bcs $f7d0 bcs _e1 +.f7cd 20 09 ed jsr $ed09 jsr kernel.device.open +.f7d0 fa plx _e1 plx +.f7d1 b0 10 bcs $f7e3 bcs _out + + ; Init and open the second PS2 device. +.f7d3 da phx phx +.f7d4 8a txa txa +.f7d5 a0 03 ldy #$03 ldy #irq.ps2_1 +.f7d7 20 3a fc jsr $fc3a jsr hardware.ps2.init +.f7da b0 03 bcs $f7df bcs _e2 +.f7dc 20 09 ed jsr $ed09 jsr kernel.device.open +.f7df fa plx _e2 plx +.f7e0 b0 01 bcs $f7e3 bcs _out + +.f7e2 18 clc clc +.f7e3 60 rts _out rts + + + .send + .endn + .endn + + + +;****** Processing input file: platform/jr/console.asm + + ; OpenKERNAL - a clean-room implementation of the C64's KERNAL ABI. + ; Copyright 2022 Jessie Oberreuter . + ; SPDX-License-Identifier: GPL-3.0-only + + ; Low level Console driver. + ; TODO: move screen editor to kernel. + + .cpu "w65c02" + + .namespace platform + console .namespace + + * = $c000 +>c000 00 00 00 00 00 00 00 00 .binary "platform/jr/Bm437_PhoenixEGA_8x8.bin" +>c008 7e 81 a5 81 bd 99 81 7e 3c 7e db ff c3 7e 3c 00 +>c018 00 ee fe fe 7c 38 10 00 10 38 7c fe 7c 38 10 00 +>c028 00 3c 18 ff ff 08 18 00 10 38 7c fe fe 10 38 00 +>c038 00 00 18 3c 18 00 00 00 ff ff e7 c3 e7 ff ff ff +>c048 00 3c 42 81 81 42 3c 00 ff c3 bd 7e 7e bd c3 ff +>c058 01 03 07 0f 1f 3f 7f ff ff fe fc f8 f0 e0 c0 80 +>c068 04 06 07 04 04 fc f8 00 0c 0a 0d 0b f9 f9 1f 1f +>c078 00 92 7c 44 c6 7c 92 00 00 00 60 78 7e 78 60 00 +>c088 00 00 06 1e 7e 1e 06 00 18 7e 18 18 18 18 7e 18 +>c098 66 66 66 66 66 00 66 00 ff b6 76 36 36 36 36 00 +>c0a8 7e c1 dc 22 22 1f 83 7e 00 00 00 7e 7e 00 00 00 +>c0b8 18 7e 18 18 7e 18 00 ff 18 7e 18 18 18 18 18 00 +>c0c8 18 18 18 18 18 7e 18 00 00 04 06 ff 06 04 00 00 +>c0d8 00 20 60 ff 60 20 00 00 00 00 00 c0 c0 c0 ff 00 +>c0e8 00 24 66 ff 66 24 00 00 00 00 10 38 7c fe 00 00 +>c0f8 00 00 00 fe 7c 38 10 00 00 00 00 00 00 00 00 00 +>c108 30 30 30 30 30 00 30 00 66 66 00 00 00 00 00 00 +>c118 6c 6c fe 6c fe 6c 6c 00 10 7c d2 7c 86 7c 10 00 +>c128 f0 96 fc 18 3e 72 de 00 30 48 30 78 ce cc 78 00 +>c138 0c 0c 18 00 00 00 00 00 10 60 c0 c0 c0 60 10 00 +>c148 10 0c 06 06 06 0c 10 00 00 54 38 fe 38 54 00 00 +>c158 00 18 18 7e 18 18 00 00 00 00 00 00 00 00 18 70 +>c168 00 00 00 7e 00 00 00 00 00 00 00 00 00 00 18 00 +>c178 02 06 0c 18 30 60 c0 00 7c ce de f6 e6 e6 7c 00 +>c188 18 38 78 18 18 18 3c 00 7c c6 06 0c 30 60 fe 00 +>c198 7c c6 06 3c 06 c6 7c 00 0e 1e 36 66 fe 06 06 00 +>c1a8 fe c0 c0 fc 06 06 fc 00 7c c6 c0 fc c6 c6 7c 00 +>c1b8 fe 06 0c 18 30 60 60 00 7c c6 c6 7c c6 c6 7c 00 +>c1c8 7c c6 c6 7e 06 c6 7c 00 00 30 00 00 00 30 00 00 +>c1d8 00 30 00 00 00 30 20 00 00 1c 30 60 30 1c 00 00 +>c1e8 00 00 7e 00 7e 00 00 00 00 70 18 0c 18 70 00 00 +>c1f8 7c c6 0c 18 30 00 30 00 7c 82 9a aa aa 9e 7c 00 +>c208 7c c6 c6 fe c6 c6 c6 00 fc 66 66 7c 66 66 fc 00 +>c218 7c c6 c0 c0 c0 c6 7c 00 fc 66 66 66 66 66 fc 00 +>c228 fe 62 68 78 68 62 fe 00 fe 62 68 78 68 60 f0 00 +>c238 7c c6 c6 c0 de c6 7c 00 c6 c6 c6 fe c6 c6 c6 00 +>c248 3c 18 18 18 18 18 3c 00 1e 0c 0c 0c 0c cc 78 00 +>c258 c6 cc d8 f0 d8 cc c6 00 f0 60 60 60 60 62 fe 00 +>c268 c6 ee fe d6 c6 c6 c6 00 c6 e6 f6 de ce c6 c6 00 +>c278 7c c6 c6 c6 c6 c6 7c 00 fc 66 66 7c 60 60 f0 00 +>c288 7c c6 c6 c6 c6 c6 7c 0c fc 66 66 7c 66 66 e6 00 +>c298 7c c6 c0 7c 06 c6 7c 00 7e 5a 18 18 18 18 3c 00 +>c2a8 c6 c6 c6 c6 c6 c6 7c 00 c6 c6 c6 c6 c6 6c 38 00 +>c2b8 c6 c6 c6 c6 d6 ee c6 00 c6 6c 38 38 38 6c c6 00 +>c2c8 66 66 66 3c 18 18 3c 00 fe c6 0c 18 30 66 fe 00 +>c2d8 1c 18 18 18 18 18 1c 00 c0 60 30 18 0c 06 02 00 +>c2e8 70 30 30 30 30 30 70 00 00 00 10 38 6c c6 00 00 +>c2f8 00 00 00 00 00 00 00 ff 30 30 18 00 00 00 00 00 +>c308 00 00 7c 06 7e c6 7e 00 c0 c0 fc c6 c6 c6 fc 00 +>c318 00 00 7c c6 c0 c6 7c 00 06 06 7e c6 c6 c6 7e 00 +>c328 00 00 7c c6 fe c0 7c 00 3c 66 60 f0 60 60 60 00 +>c338 00 00 7e c6 c6 7e 06 7c c0 c0 fc c6 c6 c6 c6 00 +>c348 18 00 38 18 18 18 3c 00 00 0c 00 1c 0c 0c cc 78 +>c358 c0 c0 c6 d8 f0 d8 c6 00 38 18 18 18 18 18 3c 00 +>c368 00 00 ee fe d6 c6 c6 00 00 00 fc c6 c6 c6 c6 00 +>c378 00 00 7c c6 c6 c6 7c 00 00 00 fc c6 c6 fc c0 c0 +>c388 00 00 7e c6 c6 7e 06 06 00 00 de 76 60 60 60 00 +>c398 00 00 7c c0 7c 06 7c 00 18 18 7e 18 18 18 1e 00 +>c3a8 00 00 c6 c6 c6 c6 7e 00 00 00 c6 c6 c6 6c 38 00 +>c3b8 00 00 c6 c6 d6 fe c6 00 00 00 c6 6c 38 6c c6 00 +>c3c8 00 00 c6 c6 c6 7e 06 7c 00 00 fe 0c 18 60 fe 00 +>c3d8 0e 18 18 70 18 18 0e 00 18 18 18 00 18 18 18 00 +>c3e8 e0 30 30 1c 30 30 e0 00 00 00 70 9a 0e 00 00 00 +>c3f8 00 00 18 3c 66 ff 00 00 7c c6 c0 c0 c6 7c 18 70 +>c408 66 00 c6 c6 c6 c6 7e 00 0e 18 7c c6 fe c0 7c 00 +>c418 18 24 7c 06 7e c6 7e 00 66 00 7c 06 7e c6 7e 00 +>c428 38 0c 7c 06 7e c6 7e 00 18 00 7c 06 7e c6 7e 00 +>c438 00 00 7c c0 c0 7c 18 70 18 24 7c c6 fe c0 7c 00 +>c448 66 00 7c c6 fe c0 7c 00 70 18 7c c6 fe c0 7c 00 +>c458 66 00 38 18 18 18 3c 00 18 24 38 18 18 18 3c 00 +>c468 38 0c 38 18 18 18 3c 00 66 00 7c c6 fe c6 c6 00 +>c478 18 00 7c c6 fe c6 c6 00 0e 18 fe 60 78 60 fe 00 +>c488 00 00 7c 1a 7e d8 7e 00 7e d8 d8 de f8 d8 de 00 +>c498 18 24 7c c6 c6 c6 7c 00 66 00 7c c6 c6 c6 7c 00 +>c4a8 38 0c 7c c6 c6 c6 7c 00 18 24 c6 c6 c6 c6 7e 00 +>c4b8 38 0c c6 c6 c6 c6 7e 00 66 00 c6 c6 c6 7e 06 7c +>c4c8 66 7c c6 c6 c6 c6 7c 00 c6 00 c6 c6 c6 c6 7c 00 +>c4d8 18 7c c6 c0 c6 7c 18 00 1e 32 30 78 30 70 fe 00 +>c4e8 66 3c 18 7e 18 3c 18 00 fc c6 fc c0 cc de cc 0e +>c4f8 00 1c 32 30 fc 30 f0 00 0e 18 7c 06 7e c6 7e 00 +>c508 1a 30 38 18 18 18 3c 00 0e 18 7c c6 c6 c6 7c 00 +>c518 0e 18 c6 c6 c6 c6 7e 00 66 98 fc c6 c6 c6 c6 00 +>c528 66 98 e6 f6 de ce c6 00 7c 06 7e c6 7e 00 fe 00 +>c538 7c c6 c6 c6 7c 00 fe 00 18 00 18 30 60 c6 7c 00 +>c548 00 00 fe c0 c0 c0 c0 00 00 00 fe 06 06 06 06 00 +>c558 c0 c0 c0 de 06 0c 1e 00 c0 c0 c0 cc 1c 3e 0c 00 +>c568 30 00 30 30 30 30 30 00 00 36 6c d8 6c 36 00 00 +>c578 00 d8 6c 36 6c d8 00 00 aa aa aa aa aa aa aa aa +>c588 aa 55 aa 55 aa 55 aa 55 44 22 44 22 44 22 44 22 +>c598 18 18 18 18 18 18 18 18 18 18 18 f8 18 18 18 18 +>c5a8 18 18 18 f8 18 f8 18 18 36 36 36 f6 36 36 36 36 +>c5b8 00 00 00 fe 36 36 36 36 00 00 00 f8 18 f8 18 18 +>c5c8 36 36 36 f6 06 f6 36 36 36 36 36 36 36 36 36 36 +>c5d8 00 00 00 fe 06 f6 36 36 36 36 36 f6 06 fe 00 00 +>c5e8 36 36 36 fe 00 00 00 00 18 18 18 f8 18 f8 00 00 +>c5f8 00 00 00 f8 18 18 18 18 18 18 18 1f 00 00 00 00 +>c608 18 18 18 ff 00 00 00 00 00 00 00 ff 18 18 18 18 +>c618 18 18 18 1f 18 18 18 18 00 00 00 ff 00 00 00 00 +>c628 18 18 18 ff 18 18 18 18 18 18 18 1f 18 1f 18 18 +>c638 36 36 36 37 36 36 36 36 36 36 36 37 30 3f 00 00 +>c648 00 00 00 3f 30 37 36 36 36 36 36 f7 00 ff 00 00 +>c658 00 00 00 ff 00 f7 36 36 36 36 36 37 30 37 36 36 +>c668 00 00 00 ff 00 ff 00 00 36 36 36 f7 00 f7 36 36 +>c678 18 18 18 ff 00 ff 00 00 36 36 36 ff 00 00 00 00 +>c688 00 00 00 ff 00 ff 18 18 00 00 00 ff 36 36 36 36 +>c698 36 36 36 3f 00 00 00 00 18 18 18 1f 18 1f 00 00 +>c6a8 00 00 00 1f 18 1f 18 18 00 00 00 3f 36 36 36 36 +>c6b8 36 36 36 ff 36 36 36 36 18 18 18 ff 18 ff 18 18 +>c6c8 18 18 18 f8 00 00 00 00 00 00 00 1f 18 18 18 18 +>c6d8 ff ff ff ff ff ff ff ff 00 00 00 00 ff ff ff ff +>c6e8 f0 f0 f0 f0 f0 f0 f0 f0 0f 0f 0f 0f 0f 0f 0f 0f +>c6f8 ff ff ff ff 00 00 00 00 00 00 77 98 98 77 00 00 +>c708 1c 36 66 fc c6 c6 fc c0 fe 62 60 60 60 60 60 00 +>c718 00 00 ff 66 66 66 66 00 fe 62 30 18 30 62 fe 00 +>c728 00 00 3f 66 c6 cc 78 00 00 00 33 33 33 3e 30 f0 +>c738 00 00 ff 18 18 18 18 00 3c 18 3c 66 66 3c 18 3c +>c748 00 7c c6 fe c6 7c 00 00 00 7e c3 c3 c3 66 e7 00 +>c758 1e 19 3c 66 c6 cc 78 00 00 00 66 99 99 66 00 00 +>c768 00 03 7c ce e6 7c c0 00 00 3e c0 fe c0 3e 00 00 +>c778 00 7e c3 c3 c3 c3 00 00 00 fe 00 fe 00 fe 00 00 +>c788 18 18 7e 18 18 7e 00 00 70 18 0c 18 70 00 fe 00 +>c798 1c 30 60 30 1c 00 fe 00 00 0e 1b 18 18 18 18 18 +>c7a8 18 18 18 18 18 d8 70 00 00 18 00 7e 00 18 00 00 +>c7b8 00 76 dc 00 76 dc 00 00 3c 66 3c 00 00 00 00 00 +>c7c8 00 18 3c 18 00 00 00 00 00 00 00 00 18 00 00 00 +>c7d8 0f 0c 0c 0c ec 6c 38 00 d8 ec cc cc 00 00 00 00 +>c7e8 f0 30 c0 f0 00 00 00 00 00 00 00 3c 3c 3c 3c 00 +>c7f8 00 00 00 00 00 00 00 00 + + +=60 ROWS = 60 +=80 COLS = 80 +=4 TABS = 4 + + + ; IO PAGE 0 +=$d800 TEXT_LUT_FG = $D800 +=$d840 TEXT_LUT_BG = $D840 + ; Text Memory +=$c000 TEXT_MEM = $C000 ; IO Page 2 +=$c000 COLOR_MEM = $C000 ; IO Page 3 + + .section dp +>00dd src .word ? +>00df dest .word ? +>00e1 count .word ? + +>00e3 cur_x .byte ? +>00e4 cur_y .byte ? +>00e5 ptr .word ? +>00e7 color .byte ? +>00e8 rev .byte ? + .send + + + .section kernel + +.f7e4 init +.f7e4 20 f2 f7 jsr $f7f2 jsr TinyVky_Init +.f7e7 a9 e6 lda #$e6 lda #$e6 +.f7e9 85 e7 sta $e7 sta color +.f7eb 64 e8 stz $e8 stz rev +.f7ed 20 14 f9 jsr $f914 jsr cls + +.f7f0 18 clc clc +.f7f1 60 rts rts + + +.f7f2 TinyVky_Init: +.f7f2 64 01 stz $01 stz $1 + +.f7f4 9c 00 d0 stz $d000 stz MASTER_CTRL_REG_L ; Everything off during init. +.f7f7 9c 01 d0 stz $d001 stz MASTER_CTRL_REG_H ; 640x480 + +.f7fa a9 01 lda #$01 lda #Mstr_Ctrl_Text_Mode_En; +.f7fc 8d 00 d0 sta $d000 sta MASTER_CTRL_REG_L + +.f7ff 20 0f f8 jsr $f80f jsr init_text_palette +.f802 20 a8 f8 jsr $f8a8 jsr init_border +.f805 20 b5 f8 jsr $f8b5 jsr init_font +.f808 20 60 f8 jsr $f860 jsr init_graphics_palettes + + ; We'll manage our own cursor +.f80b 9c 10 d0 stz $d010 stz VKY_TXT_CURSOR_CTRL_REG + +.f80e 60 rts rts + +.f80f init_text_palette + +.f80f a2 00 ldx #$00 ldx #0 +.f811 bd 20 f8 lda $f820,x _loop lda _palette,x +.f814 9d 00 d8 sta $d800,x sta TEXT_LUT_FG,x +.f817 9d 40 d8 sta $d840,x sta TEXT_LUT_BG,x +.f81a e8 inx inx +.f81b e0 40 cpx #$40 cpx #64 +.f81d d0 f2 bne $f811 bne _loop +.f81f 60 rts rts +.f820 _palette +>f820 00 00 00 00 .dword $000000 +>f824 ff ff ff 00 .dword $ffffff +>f828 00 00 88 00 .dword $880000 +>f82c ee ff aa 00 .dword $aaffee +>f830 cc 44 cc 00 .dword $cc44cc +>f834 55 cc 00 00 .dword $00cc55 +>f838 aa 00 00 00 .dword $0000aa +>f83c 77 dd dd 00 .dword $dddd77 +>f840 55 88 dd 00 .dword $dd8855 +>f844 00 44 66 00 .dword $664400 +>f848 77 77 ff 00 .dword $ff7777 +>f84c 33 33 33 00 .dword $333333 +>f850 77 77 77 00 .dword $777777 +>f854 66 ff aa 00 .dword $aaff66 +>f858 ff 88 00 00 .dword $0088ff +>f85c bb bb bb 00 .dword $bbbbbb + +.f860 init_graphics_palettes + +.f860 da phx phx +.f861 5a phy phy + + ; Save I/O page +.f862 a4 01 ldy $01 ldy $1 + + ; Switch to I/O Page 1 (font and color LUTs) +.f864 a9 01 lda #$01 lda #1 +.f866 85 01 sta $01 sta $1 + + ; Init ptr +.f868 64 e5 stz $e5 stz ptr+0 +.f86a a9 d0 lda #$d0 lda #$d0 +.f86c 85 e6 sta $e6 sta ptr+1 + +.f86e a2 00 ldx #$00 ldx #0 ; Starting color byte. +.f870 _loop + ; Write the next color entry +.f870 20 8a f8 jsr $f88a jsr write_bgra +.f873 e8 inx inx + + ; Advance the pointer; X will wrap around on its own + +.f874 a5 e5 lda $e5 lda ptr +.f876 69 04 adc #$04 adc #4 +.f878 85 e5 sta $e5 sta ptr +.f87a d0 f4 bne $f870 bne _loop + +.f87c a5 e6 lda $e6 lda ptr+1 +.f87e 1a inc a inc a +.f87f 85 e6 sta $e6 sta ptr+1 +.f881 c9 e0 cmp #$e0 cmp #$e0 +.f883 d0 eb bne $f870 bne _loop + + ; Restore I/O page +.f885 84 01 sty $01 sty $1 + +.f887 7a ply ply +.f888 fa plx plx +.f889 60 rts rts + +.f88a write_bgra + ; X = rrrgggbb + ; A palette entry consists of four consecutive bytes: B, G, R, A. + +.f88a 5a phy phy +.f88b a0 03 ldy #$03 ldy #3 ; Working backwards: A,R,G,B + + ; Write the Alpha value +.f88d a9 ff lda #$ff lda #255 +.f88f 20 9e f8 jsr $f89e jsr _write + + ; Write the RGB values +.f892 8a txa txa +.f893 88 dey _loop dey +.f894 30 05 bmi $f89b bmi _done +.f896 20 9e f8 jsr $f89e jsr _write +.f899 80 f8 bra $f893 bra _loop + +.f89b 7a ply _done ply +.f89c 18 clc clc +.f89d 60 rts rts + +.f89e _write + ; Write the upper bits to (ptr),y +.f89e 48 pha pha +.f89f 29 e0 and #$e0 and #%111_00000 +.f8a1 91 e5 sta ($e5),y sta (ptr),y +.f8a3 68 pla pla + + ; Shift in the next set of bits (blue truncated, alpha zero). +.f8a4 0a asl a asl a +.f8a5 0a asl a asl a +.f8a6 0a asl a asl a + +.f8a7 60 rts rts + +.f8a8 init_border +.f8a8 9c 04 d0 stz $d004 stz BORDER_CTRL_REG +.f8ab 9c 07 d0 stz $d007 stz BORDER_COLOR_R +.f8ae 9c 06 d0 stz $d006 stz BORDER_COLOR_G +.f8b1 9c 05 d0 stz $d005 stz BORDER_COLOR_B +.f8b4 60 rts rts + + +.f8b5 init_font: +.f8b5 a5 01 lda $01 lda $1 +.f8b7 48 pha pha + +.f8b8 a9 01 lda #$01 lda #1 +.f8ba 85 01 sta $01 sta $1 +.f8bc 20 c4 f8 jsr $f8c4 jsr _install + +.f8bf 68 pla pla +.f8c0 85 01 sta $01 sta $1 + +.f8c2 18 clc clc +.f8c3 60 rts rts + +.f8c4 _install +.f8c4 da phx phx +.f8c5 5a phy phy + +.f8c6 64 dd stz $dd stz src+0 +.f8c8 64 df stz $df stz dest+0 +.f8ca a9 c0 lda #$c0 lda #$c0 +.f8cc 85 de sta $de sta src+1 +.f8ce a9 c4 lda #$c4 lda #$c4 +.f8d0 85 e0 sta $e0 sta dest+1 + +.f8d2 a2 04 ldx #$04 ldx #4 +.f8d4 a0 00 ldy #$00 ldy #0 +.f8d6 _loop +.f8d6 a7 01 smb 2,$01 smb 2,$1 +.f8d8 b1 dd lda ($dd),y lda (src),y +.f8da 27 01 rmb 2,$01 rmb 2,$1 +.f8dc 4a lsr a lsr a ; Jr is dropping the first pixel. +.f8dd 91 dd sta ($dd),y sta (src),y +.f8df 49 ff eor #$ff eor #$ff +.f8e1 91 df sta ($df),y sta (dest),y +.f8e3 c8 iny iny +.f8e4 d0 f0 bne $f8d6 bne _loop +.f8e6 e6 de inc $de inc src+1 +.f8e8 e6 e0 inc $e0 inc dest+1 +.f8ea ca dex dex +.f8eb d0 e9 bne $f8d6 bne _loop + +.f8ed 7a ply ply +.f8ee fa plx plx +.f8ef 60 rts rts + +.f8f0 long_move +.f8f0 da phx phx +.f8f1 5a phy phy + +.f8f2 a0 00 ldy #$00 ldy #0 +.f8f4 a6 e2 ldx $e2 ldx count+1 +.f8f6 f0 15 beq $f90d beq _small + +.f8f8 b1 dd lda ($dd),y _large lda (src),y +.f8fa 91 df sta ($df),y sta (dest),y +.f8fc c8 iny iny +.f8fd d0 f9 bne $f8f8 bne _large +.f8ff e6 de inc $de inc src+1 +.f901 e6 e0 inc $e0 inc dest+1 +.f903 ca dex dex +.f904 d0 f2 bne $f8f8 bne _large +.f906 80 05 bra $f90d bra _small + +.f908 b1 dd lda ($dd),y _loop lda (src),y +.f90a 91 df sta ($df),y sta (dest),y + +.f90c c8 iny iny +.f90d c4 e1 cpy $e1 _small cpy count +.f90f d0 f7 bne $f908 bne _loop + +.f911 7a ply ply +.f912 fa plx plx +.f913 60 rts rts + +.f914 cls +.f914 48 pha pha +.f915 da phx phx +.f916 5a phy phy + +.f917 a9 02 lda #$02 lda #2 +.f919 85 01 sta $01 sta $1 +.f91b a9 20 lda #$20 lda #' ' +.f91d 20 34 f9 jsr $f934 jsr _fill + +.f920 a9 03 lda #$03 lda #3 +.f922 85 01 sta $01 sta $1 +.f924 a5 e7 lda $e7 lda color +.f926 20 34 f9 jsr $f934 jsr _fill + +.f929 a2 00 ldx #$00 ldx #0 +.f92b a0 00 ldy #$00 ldy #0 +.f92d 20 49 f9 jsr $f949 jsr gotoxy + +.f930 7a ply ply +.f931 fa plx plx +.f932 68 pla pla +.f933 60 rts rts + +.f934 _fill +.f934 64 e5 stz $e5 stz ptr+0 +.f936 a0 c0 ldy #$c0 ldy #$c0 +.f938 84 e6 sty $e6 sty ptr+1 +.f93a a2 14 ldx #$14 ldx #$14 +.f93c a0 00 ldy #$00 ldy #0 +.f93e 91 e5 sta ($e5),y _loop sta (ptr),y +.f940 c8 iny iny +.f941 d0 fb bne $f93e bne _loop +.f943 e6 e6 inc $e6 inc ptr+1 +.f945 ca dex dex +.f946 d0 f6 bne $f93e bne _loop +.f948 60 rts rts + + +.f949 gotoxy +.f949 86 e3 stx $e3 stx cur_x +.f94b 84 e4 sty $e4 sty cur_y + + ; 80 = 64 + 16 = 0101 0000 + +.f94d 64 e6 stz $e6 stz ptr+1 +.f94f 98 tya tya +.f950 c0 3c cpy #$3c cpy #60 +.f952 90 02 bcc $f956 bcc _ok +.f954 a0 3b ldy #$3b ldy #59 +.f956 _ok +.f956 0a asl a asl a ; x2 +.f957 0a asl a asl a ; x4 +.f958 26 e6 rol $e6 rol ptr+1 +.f95a 65 e4 adc $e4 adc cur_y ; x5 +.f95c 90 02 bcc $f960 bcc _nc +.f95e e6 e6 inc $e6 inc ptr+1 +.f960 0a asl a _nc asl a ; x10 +.f961 26 e6 rol $e6 rol ptr+1 +.f963 0a asl a asl a ; x20 +.f964 26 e6 rol $e6 rol ptr+1 +.f966 0a asl a asl a ; x40 +.f967 26 e6 rol $e6 rol ptr+1 +.f969 0a asl a asl a ; x80 +.f96a 26 e6 rol $e6 rol ptr+1 +.f96c 85 e5 sta $e5 sta ptr+0 + +.f96e a5 e6 lda $e6 lda ptr+1 +.f970 69 c0 adc #$c0 adc #$c0 +.f972 85 e6 sta $e6 sta ptr+1 + + ; Save/restore the state of the i/o bit + ; while moving the cursor. +.f974 a5 01 lda $01 lda $1 +.f976 48 pha pha +.f977 a9 02 lda #$02 lda #2 +.f979 85 01 sta $01 sta $1 +.f97b 20 82 f9 jsr $f982 jsr cursor +.f97e 68 pla pla +.f97f 85 01 sta $01 sta $1 +.f981 60 rts rts + +.f982 cursor +.f982 a4 e3 ldy $e3 ldy cur_x + +.f984 a2 03 ldx #$03 ldx #3 ; color memory +.f986 86 01 stx $01 stx $1 +.f988 b1 e5 lda ($e5),y lda (ptr),y +.f98a 64 01 stz $01 stz $1 +.f98c 8d 13 d0 sta $d013 sta VKY_TXT_CURSOR_COLR_REG + +.f98f a2 02 ldx #$02 ldx #2 ; text memory +.f991 86 01 stx $01 stx $1 +.f993 b1 e5 lda ($e5),y lda (ptr),y +.f995 49 80 eor #$80 eor #$80 +.f997 64 01 stz $01 stz $1 +.f999 8d 12 d0 sta $d012 sta VKY_TXT_CURSOR_CHAR_REG + +.f99c a5 e3 lda $e3 lda cur_x +.f99e 8d 14 d0 sta $d014 sta VKY_TXT_CURSOR_X_REG_L +.f9a1 9c 15 d0 stz $d015 stz VKY_TXT_CURSOR_X_REG_H + +.f9a4 a5 e4 lda $e4 lda cur_y +.f9a6 8d 16 d0 sta $d016 sta VKY_TXT_CURSOR_Y_REG_L +.f9a9 9c 17 d0 stz $d017 stz VKY_TXT_CURSOR_Y_REG_H + +.f9ac a9 0b lda #$0b lda #Vky_Cursor_Enable | Vky_Cursor_Flash_Rate0 | 8 +.f9ae 8d 10 d0 sta $d010 sta VKY_TXT_CURSOR_CTRL_REG +.f9b1 9c 11 d0 stz $d011 stz VKY_TXT_START_ADD_PTR + +.f9b4 a2 02 ldx #$02 ldx #2 +.f9b6 86 01 stx $01 stx $1 + +.f9b8 60 rts rts + + +.f9b9 puts +.f9b9 putc +.f9b9 48 pha pha +.f9ba da phx phx +.f9bb 5a phy phy + +.f9bc a6 01 ldx $01 ldx $1 +.f9be da phx phx + +.f9bf a2 02 ldx #$02 ldx #2 +.f9c1 86 01 stx $01 stx $1 + +.f9c3 20 d4 f9 jsr $f9d4 jsr _putc +.f9c6 a6 e3 ldx $e3 ldx cur_x +.f9c8 a4 e4 ldy $e4 ldy cur_y +.f9ca 20 49 f9 jsr $f949 jsr gotoxy + +.f9cd fa plx plx +.f9ce 86 01 stx $01 stx $1 + +.f9d0 7a ply ply +.f9d1 fa plx plx +.f9d2 68 pla pla +.f9d3 60 rts rts + +.f9d4 _putc + +.f9d4 a6 e3 ldx $e3 ldx cur_x +.f9d6 a4 e4 ldy $e4 ldy cur_y +.f9d8 48 pha pha +.f9d9 20 49 f9 jsr $f949 jsr gotoxy ; Init line ptr; TODO: just init line ptr +.f9dc 68 pla pla + +.f9dd c9 20 cmp #$20 cmp #$20 +.f9df 90 07 bcc $f9e8 bcc _ctrl + +.f9e1 c9 80 cmp #$80 cmp #$80 +.f9e3 b0 3a bcs $fa1f bcs cbm + +.f9e5 4c ba fa jmp $faba jmp insert + +.f9e8 _ctrl +.f9e8 c9 05 cmp #$05 cmp #5 ; CBM white; occludes ^e->eol below +.f9ea f0 33 beq $fa1f beq cbm +.f9ec c9 11 cmp #$11 cmp #17 +.f9ee 90 07 bcc $f9f7 bcc _indexed +.f9f0 c9 1b cmp #$1b cmp #27 ; esc +.f9f2 d0 2b bne $fa1f bne cbm +.f9f4 4c 63 fa jmp $fa63 jmp esc + +.f9f7 _indexed +.f9f7 0a asl a asl a +.f9f8 aa tax tax +.f9f9 7c fc f9 jmp ($f9fc,x) jmp (_table,x) +.f9fc _table +>f9fc 1e fa .word ignore ; Key is only for documentation. +>f9fe 91 fa .word begin ; Key is only for documentation. +>fa00 6c fa .word left ; Key is only for documentation. +>fa02 1e fa .word ignore ; Key is only for documentation. +>fa04 1e fa .word ignore ; Key is only for documentation. +>fa06 94 fa .word end ; Key is only for documentation. +>fa08 73 fa .word right ; Key is only for documentation. +>fa0a ad fa .word bell ; Key is only for documentation. +>fa0c a3 fa .word backspace ; Key is only for documentation. +>fa0e ae fa .word tab ; Key is only for documentation. +>fa10 53 fa .word lf ; Key is only for documentation. +>fa12 d0 fa .word kill ; Key is only for documentation. +>fa14 64 fa .word ff ; Key is only for documentation. +>fa16 54 fa .word cr ; Key is only for documentation. +>fa18 84 fa .word down ; Key is only for documentation. +>fa1a 1e fa .word ignore ; Key is only for documentation. +>fa1c 7c fa .word up ; Key is only for documentation. + +.fa1e 60 rts ignore rts + + ctrl .macro key, function + .endm + +.fa1f cbm + ; Slower, but I can far-jump +.fa1f a2 00 ldx #$00 ldx #0 +.fa21 dd 33 fa cmp $fa33,x _loop cmp _table,x +.fa24 f0 0a beq $fa30 beq _found +.fa26 e8 inx inx +.fa27 e8 inx inx +.fa28 e8 inx inx +.fa29 e0 18 cpx #$18 cpx #_end +.fa2b d0 f4 bne $fa21 bne _loop +.fa2d 4c f3 fa jmp $faf3 jmp set_color ; maybe it's a color command + +.fa30 7c 34 fa jmp ($fa34,x) _found jmp (_table+1,x) + +.fa33 _table +>fa33 11 .byte $11 +>fa34 84 fa .word down +>fa36 12 .byte $12 +>fa37 4b fa .word reverse +>fa39 13 .byte $13 +>fa3a 67 fa .word home +>fa3c 14 .byte $14 +>fa3d a3 fa .word backspace +>fa3f 1d .byte $1d +>fa40 73 fa .word right +>fa42 91 .byte $91 +>fa43 53 fa .word lf +>fa45 92 .byte $92 +>fa46 50 fa .word unreverse +>fa48 93 .byte $93 +>fa49 14 f9 .word cls +=24 _end = * - _table + + entry .macro code, function + .endm + +.fa4b reverse +.fa4b a2 80 ldx #$80 ldx #128 +.fa4d 86 e8 stx $e8 stx rev +.fa4f 60 rts rts + +.fa50 unreverse +.fa50 64 e8 stz $e8 stz rev +.fa52 60 rts rts + +.fa53 60 rts lf rts + +.fa54 cr +.fa54 64 e3 stz $e3 stz cur_x +.fa56 _lf +.fa56 a4 e4 ldy $e4 ldy cur_y +.fa58 c8 iny iny +.fa59 c0 3c cpy #$3c cpy #ROWS +.fa5b d0 03 bne $fa60 bne _out +.fa5d 4c dc fa jmp $fadc jmp scroll +.fa60 _out +.fa60 84 e4 sty $e4 sty cur_y +.fa62 60 rts rts + +.fa63 esc +.fa63 60 rts rts ; TODO: vt100 sequences + +.fa64 ff +.fa64 4c 14 f9 jmp $f914 jmp cls + +.fa67 home +.fa67 64 e3 stz $e3 stz cur_x +.fa69 64 e4 stz $e4 stz cur_y +.fa6b 60 rts rts + +.fa6c left +.fa6c a5 e3 lda $e3 lda cur_x +.fa6e f0 02 beq $fa72 beq _out +.fa70 c6 e3 dec $e3 dec cur_x +.fa72 60 rts _out rts + +.fa73 right +.fa73 a5 e3 lda $e3 lda cur_x +.fa75 c9 4f cmp #$4f cmp #COLS-1 +.fa77 b0 02 bcs $fa7b bcs _out +.fa79 e6 e3 inc $e3 inc cur_x +.fa7b 60 rts _out rts + +.fa7c up +.fa7c a5 e4 lda $e4 lda cur_y +.fa7e 3a dec a dec a +.fa7f 30 02 bmi $fa83 bmi _out +.fa81 85 e4 sta $e4 sta cur_y +.fa83 60 rts _out rts + +.fa84 down +.fa84 a5 e4 lda $e4 lda cur_y +.fa86 1a inc a inc a +.fa87 c9 3c cmp #$3c cmp #ROWS +.fa89 d0 03 bne $fa8e bne _okay +.fa8b 4c dc fa jmp $fadc jmp scroll +.fa8e 85 e4 sta $e4 _okay sta cur_y +.fa90 60 rts rts + +.fa91 begin +.fa91 64 e3 stz $e3 stz cur_x +.fa93 60 rts rts + +.fa94 end +.fa94 a0 50 ldy #$50 ldy #COLS +.fa96 88 dey _loop dey +.fa97 f0 06 beq $fa9f beq _done +.fa99 b1 e5 lda ($e5),y lda (ptr),y +.fa9b c9 20 cmp #$20 cmp #32 +.fa9d f0 f7 beq $fa96 beq _loop +.fa9f 84 e3 sty $e3 _done sty cur_x +.faa1 80 d0 bra $fa73 bra right + +.faa3 backspace +.faa3 20 6c fa jsr $fa6c jsr left +.faa6 a4 e3 ldy $e3 ldy cur_x +.faa8 a9 20 lda #$20 lda #32 +.faaa 91 e5 sta ($e5),y sta (ptr),y +.faac 60 rts rts + +.faad bell +.faad 60 rts rts ; TODO: flash or support sound + +.faae tab +.faae a9 20 lda #$20 lda #32 +.fab0 20 ba fa jsr $faba jsr insert +.fab3 a5 e3 lda $e3 lda cur_x +.fab5 29 03 and #$03 and #TABS-1 +.fab7 d0 f5 bne $faae bne tab +.fab9 60 rts rts + +.faba insert + ; ASCII for the rest + ; Someone else can do PETSCII +.faba a4 e3 ldy $e3 ldy cur_x +.fabc 05 e8 ora $e8 ora rev +.fabe 91 e5 sta ($e5),y sta (ptr),y +.fac0 e6 01 inc $01 inc $1 +.fac2 a5 e7 lda $e7 lda color +.fac4 91 e5 sta ($e5),y sta (ptr),y +.fac6 c6 01 dec $01 dec $1 +.fac8 c8 iny iny +.fac9 c0 50 cpy #$50 cpy #COLS +.facb f0 87 beq $fa54 beq cr +.facd 84 e3 sty $e3 sty cur_x +.facf 60 rts _done rts + +.fad0 kill +.fad0 a4 e3 ldy $e3 ldy cur_x +.fad2 a9 20 lda #$20 lda #32 +.fad4 91 e5 sta ($e5),y _loop sta (ptr),y +.fad6 c8 iny iny +.fad7 c0 50 cpy #$50 cpy #COLS +.fad9 d0 f9 bne $fad4 bne _loop +.fadb 60 rts rts + +.fadc scroll +.fadc a9 c0 lda #$c0 lda #$c0 +.fade 85 de sta $de sta src+1 +.fae0 85 e0 sta $e0 sta dest+1 + +.fae2 a9 50 lda #$50 lda #80 +.fae4 85 dd sta $dd sta src +.fae6 64 df stz $df stz dest + +.fae8 a9 c0 lda #$c0 lda #COLS*(ROWS) +.faee 85 e2 sta $e2 sta count+1 + +.faf0 4c f0 f8 jmp $f8f0 jmp long_move + +.faf3 set_color +.faf3 a2 00 ldx #$00 ldx #0 +.faf5 dd 0a fb cmp $fb0a,x _loop cmp _table,x +.faf8 f0 06 beq $fb00 beq _found +.fafa e8 inx inx +.fafb e0 10 cpx #$10 cpx #_end +.fafd d0 f6 bne $faf5 bne _loop +.faff 60 rts rts +.fb00 _found +.fb00 8a txa txa +.fb01 0a asl a asl a +.fb02 0a asl a asl a +.fb03 0a asl a asl a +.fb04 0a asl a asl a +.fb05 09 06 ora #$06 ora #6 +.fb07 85 e7 sta $e7 sta color +.fb09 60 rts rts +.fb0a _table +>fb0a 90 .byte $90 ; color.black +>fb0b 05 .byte $05 ; color.white +>fb0c 1c .byte $1c ; color.red +>fb0d 9f .byte $9f ; color.cyan +>fb0e 9c .byte $9c ; color.violet +>fb0f 1e .byte $1e ; color.green +>fb10 1f .byte $1f ; color.blue +>fb11 9e .byte $9e ; color.yellow +>fb12 81 .byte $81 ; color.orange +>fb13 95 .byte $95 ; color.brown +>fb14 96 .byte $96 ; color.lred +>fb15 97 .byte $97 ; color.grey1 +>fb16 98 .byte $98 ; color.grey2 +>fb17 99 .byte $99 ; color.lgreen +>fb18 9a .byte $9a ; color.blue +>fb19 9b .byte $9b ; color.grey3 +=16 _end = * - _table + + .send + .endn + .endn + + +;****** Processing input file: platform/jr/c64kbd.asm + + ; OpenKERNAL - a clean-room implementation of the C64's KERNAL ABI. + ; Copyright 2022 Jessie Oberreuter . + ; SPDX-License-Identifier: GPL-3.0-only + + ; Driver for a VIC20/C264 keyboard connected to the 6522 port. + + .cpu "w65c02" + + .namespace platform + c64kbd .namespace + + +=$dc01 PRA = $dc01 ; CIA#1 (Port Register A) +=$dc03 DDRA = $dc03 ; CIA#1 (Data Direction Register A) + +=$dc00 PRB = $dc00 ; CIA#1 (Port Register B) +=$dc02 DDRB = $dc02 ; CIA#1 (Data Direction Register B) + + .section kmem +>03aa mask .byte ? ; Copy of PRA output +>03ab hold .byte ? ; Copy of PRB during processing +>03ac bitno .byte ? ; # of the col bit being processed + .send + + .section dp ; So we can branch on bits :). +>00e9 state: .fill 8 + .send + + .section kernel + +.fb1a init: +.fb1a 64 01 stz $01 stz $1 + +.fb1c a9 ff lda #$ff lda #$ff ; CIA#1 port A = outputs +.fb1e 8d 03 dc sta $dc03 sta DDRA + +.fb21 a9 00 lda #$00 lda #$00 ; CIA#1 port B = inputs +.fb23 8d 02 dc sta $dc02 sta DDRB + + ; Init the roll-table +.fb26 a9 ff lda #$ff lda #$ff ; no key grounded +.fb28 a2 07 ldx #$07 ldx #7 +.fb2a 95 e9 sta $e9,x _loop sta state,x +.fb2c ca dex dex +.fb2d 10 fb bpl $fb2a bpl _loop +.fb2f 60 rts rts + +.fb30 scan +.fb30 64 01 stz $01 stz $1 +.fb32 a9 7f lda #$7f lda #$7f +.fb34 a2 00 ldx #$00 ldx #0 + +.fb36 _loop +.fb36 8d 01 dc sta $dc01 sta PRA +.fb39 8d aa 03 sta $03aa sta mask + +.fb3c ad 00 dc lda $dc00 lda PRB +.fb3f 8d ab 03 sta $03ab sta hold +.fb42 55 e9 eor $e9,x eor state,x +.fb44 f0 03 beq $fb49 beq _next + +.fb46 20 53 fb jsr $fb53 jsr report + +.fb49 _next +.fb49 e8 inx inx +.fb4a ad aa 03 lda $03aa lda mask +.fb4d 4a lsr a lsr a +.fb4e 09 80 ora #$80 ora #$80 +.fb50 b0 e4 bcs $fb36 bcs _loop +.fb52 60 rts rts + + +.fb53 report + + ; Current state doesn't match last state. + ; Walk the bits and report any new keys. + +.fb53 _loop ; Process any bits that differ between PRB and state,x + + ; Y->next diff bit to check +.fb53 a8 tay tay +.fb54 b9 00 e5 lda $e500,y lda irq.first_bit,y +.fb57 8d ac 03 sta $03ac sta bitno +.fb5a a8 tay tay + + ; Clear the current state for this bit +.fb5b b9 c8 f5 lda $f5c8,y lda irq.bit,y ; 'A' contains a single diff-bit +.fb5e 49 ff eor #$ff eor #$ff +.fb60 35 e9 and $e9,x and state,x +.fb62 95 e9 sta $e9,x sta state,x + + ; Report key and update the state +.fb64 b9 c8 f5 lda $f5c8,y lda irq.bit,y ; 'A' contains a single diff-bit +.fb67 2d ab 03 and $03ab and hold ; Get the state of this specific bit +.fb6a d0 05 bne $fb71 bne _save ; Key is released; no action. +.fb6c 48 pha pha +.fb6d 20 7d fb jsr $fb7d jsr _report ; Key is pressed; report it. +.fb70 68 pla pla +.fb71 _save + ; Save the state of the bit +.fb71 15 e9 ora $e9,x ora state,x +.fb73 95 e9 sta $e9,x sta state,x +.fb75 _next +.fb75 ad ab 03 lda $03ab lda hold +.fb78 55 e9 eor $e9,x eor state,x +.fb7a d0 d7 bne $fb53 bne _loop + +.fb7c 60 rts _done rts + +.fb7d _report + ; A = row # +.fb7d 8a txa txa ; Row # + + ; Bit numbers are the reverse of + ; the table order, so advance one + ; row and then "back up" by bitno. +.fb7e 1a inc a inc a + + ; A = table offset for row +.fb7f 0a asl a asl a +.fb80 0a asl a asl a +.fb81 0a asl a asl a + + ; A = table entry for key +.fb82 ed ac 03 sbc $03ac sbc bitno + + ; Y-> table entry +.fb85 a8 tay tay + +.fb86 b9 aa fb lda $fbaa,y lda keytab,y +.fb89 c9 5f cmp #$5f cmp #'_' +.fb8b f0 1c beq $fba9 beq _out ; Don't report meta keys + +.fb8d 2f e9 0e bbr 2,$e9,$fb9e bbr 2,state+0,_ctrl ; CTRL +.fb90 4f ea 0f bbr 4,$ea,$fba2 bbr 4,state+1,_shift ; RSHIFT +.fb93 7f ef 0c bbr 7,$ef,$fba2 bbr 7,state+6,_shift ; LSHIFT + +.fb96 df e9 02 bbs 5,$e9,$fb9b _alt bbs 5,state+0,_queue ; C= (ALT) +.fb99 09 80 ora #$80 ora #$80 + +.fb9b _queue +.fb9b 4c b1 ec jmp $ecb1 jmp kernel.keyboard.enque + +.fb9e _ctrl +.fb9e 29 1f and #$1f and #$1f +.fba0 80 f4 bra $fb96 bra _alt + +.fba2 _shift +.fba2 b9 ea fb lda $fbea,y lda shift,y +.fba5 c9 5f cmp #$5f cmp #'_' +.fba7 d0 ed bne $fb96 bne _alt + +.fba9 60 rts _out rts + + .enc "none" +>fbaa 5f 71 5f 20 32 5f 60 31 keytab: .text "_q_ 2_`1" +>fbb2 2f 5e 3d 5f 5f 3b 2a 7e .text "/^=__;*~" +>fbba 2c 40 3a 2e 2d 6c 70 2b .text ",@:.-lp+" +>fbc2 6e 6f 6b 6d 30 6a 69 39 .text "nokm0ji9" +>fbca 76 75 68 62 38 67 79 37 .text "vuhb8gy7" +>fbd2 78 74 66 63 36 64 72 35 .text "xtfc6dr5" +>fbda 5f 65 73 7a 34 61 77 33 .text "_esz4aw3" +>fbe2 0e 85 83 81 87 06 0d 08 .byte 'N'-64, 5+128, 3+128, 1+128, 7+128, 'F'-64, 13, 8 + +>fbea 5f 51 5f 20 22 5f 7e 21 shift: .text "_Q_ ",34,"_~!" +>fbf2 3f 5e 3d 5f 5f 5d 2a 7e .text "?^=__]*~" +>fbfa 3c 40 5b 3e 2d 4c 50 2b .text "<@[>-LP+" +>fc02 4e 4f 4b 4d 30 4a 49 29 .text "NOKM0JI)" +>fc0a 56 55 48 42 28 47 59 27 .text "VUHB(GY'" +>fc12 58 54 46 43 26 44 52 25 .text "XTFC&DR%" +>fc1a 5f 45 53 5a 24 41 57 23 .text "_ESZ$AW#" +>fc22 10 85 83 81 87 02 0d 08 .byte 'P'-64, 5+128, 3+128, 1+128, 7+128, 'B'-64, 13, 8 + + .send + .endn + .endn + + +;****** Processing input file: platform/jr/FPGA/TinyVicky_Def.asm + + ;Internal Tiny VICKY Registers and Internal Memory Locations (LUTs) + ; IO Page 0 +=$d000 MASTER_CTRL_REG_L = $D000 + ;Control Bits Fields +=$01 Mstr_Ctrl_Text_Mode_En = $01 ; Enable the Text Mode +=$02 Mstr_Ctrl_Text_Overlay = $02 ; Enable the Overlay of the text mode on top of Graphic Mode (the Background Color is ignored) +=$04 Mstr_Ctrl_Graph_Mode_En = $04 ; Enable the Graphic Mode +=$08 Mstr_Ctrl_Bitmap_En = $08 ; Enable the Bitmap Module In Vicky +=$10 Mstr_Ctrl_TileMap_En = $10 ; Enable the Tile Module in Vicky +=$20 Mstr_Ctrl_Sprite_En = $20 ; Enable the Sprite Module in Vicky +=$40 Mstr_Ctrl_GAMMA_En = $40 ; this Enable the GAMMA correction - The Analog and DVI have different color value, the GAMMA is great to correct the difference +=$80 Mstr_Ctrl_Disable_Vid = $80 ; This will disable the Scanning of the Video hence giving 100% bandwith to the CPU +=$d001 MASTER_CTRL_REG_H = $D001 + ; Reserved - TBD +=$d002 VKY_RESERVED_00 = $D002 +=$d003 VKY_RESERVED_01 = $D003 + ; +=$d004 BORDER_CTRL_REG = $D004 ; Bit[0] - Enable (1 by default) Bit[4..6]: X Scroll Offset ( Will scroll Left) (Acceptable Value: 0..7) +=$01 Border_Ctrl_Enable = $01 +=$d005 BORDER_COLOR_B = $D005 +=$d006 BORDER_COLOR_G = $D006 +=$d007 BORDER_COLOR_R = $D007 +=$d008 BORDER_X_SIZE = $D008; X- Values: 0 - 32 (Default: 32) +=$d009 BORDER_Y_SIZE = $D009; Y- Values 0 -32 (Default: 32) + ; Reserved - TBD +=$d00a VKY_RESERVED_02 = $D00A +=$d00b VKY_RESERVED_03 = $D00B +=$d00c VKY_RESERVED_04 = $D00C + ; Valid in Graphics Mode Only +=$d00d BACKGROUND_COLOR_B = $D00D ; When in Graphic Mode, if a pixel is "0" then the Background pixel is chosen +=$d00e BACKGROUND_COLOR_G = $D00E +=$d00f BACKGROUND_COLOR_R = $D00F ; + ; Cursor Registers +=$d010 VKY_TXT_CURSOR_CTRL_REG = $D010 ;[0] enable [1..2] flash rate [3] no flash +=$01 Vky_Cursor_Enable = $01 +=$02 Vky_Cursor_Flash_Rate0 = $02 +=$04 Vky_Cursor_Flash_Rate1 = $04 +=$08 Vky_Cursor_No_Flash = $08 +=$d011 VKY_TXT_START_ADD_PTR = $D011 ; This is an offset to change the Starting address of the Text Mode Buffer (in x) +=$d012 VKY_TXT_CURSOR_CHAR_REG = $D012 +=$d013 VKY_TXT_CURSOR_COLR_REG = $D013 +=$d014 VKY_TXT_CURSOR_X_REG_L = $D014 +=$d015 VKY_TXT_CURSOR_X_REG_H = $D015 +=$d016 VKY_TXT_CURSOR_Y_REG_L = $D016 +=$d017 VKY_TXT_CURSOR_Y_REG_H = $D017 + ; Line Interrupt +=$d018 VKY_LINE_IRQ_CTRL_REG = $D018 ;[0] - Enable Line 0 - WRITE ONLY +=$d019 VKY_LINE_CMP_VALUE_LO = $D019 ;Write Only [7:0] +=$d01a VKY_LINE_CMP_VALUE_HI = $D01A ;Write Only [3:0] + +=$d018 VKY_PIXEL_X_POS_LO = $D018 ; This is Where on the video line is the Pixel +=$d019 VKY_PIXEL_X_POS_HI = $D019 ; Or what pixel is being displayed when the register is read +=$d01a VKY_LINE_Y_POS_LO = $D01A ; This is the Line Value of the Raster +=$d01b VKY_LINE_Y_POS_HI = $D01B ; + +;****** Processing input file: platform/jr/FPGA/interrupt_def.asm + + ; Pending Interrupt (Read and Write Back to Clear) +=$d660 INT_PENDING_REG0 = $D660 ; +=$d661 INT_PENDING_REG1 = $D661 ; +=$d662 INT_PENDING_REG2 = $D662 ; NOT USED +=$d663 INT_PENDING_REG3 = $D663 ; NOT USED + ; Polarity Set +=$d664 INT_POL_REG0 = $D664 ; +=$d665 INT_POL_REG1 = $D665 ; +=$d666 INT_POL_REG2 = $D666 ; NOT USED +=$d667 INT_POL_REG3 = $D667 ; NOT USED + ; Edge Detection Enable +=$d668 INT_EDGE_REG0 = $D668 ; +=$d669 INT_EDGE_REG1 = $D669 ; +=$d66a INT_EDGE_REG2 = $D66A ; NOT USED +=$d66b INT_EDGE_REG3 = $D66B ; NOT USED + ; Mask +=$d66c INT_MASK_REG0 = $D66C ; +=$d66d INT_MASK_REG1 = $D66D ; +=$d66e INT_MASK_REG2 = $D66E ; NOT USED +=$d66f INT_MASK_REG3 = $D66F ; NOT USED + ; Interrupt Bit Definition + ; Register Block 0 +=$01 JR0_INT00_SOF = $01 ;Start of Frame @ 60FPS +=$02 JR0_INT01_SOL = $02 ;Start of Line (Programmable) +=$04 JR0_INT02_KBD = $04 ; +=$08 JR0_INT03_MOUSE = $08 ; +=$10 JR0_INT04_TMR0 = $10 ; +=$20 JR0_INT05_TMR1 = $20 ;Real-Time Clock Interrupt +=$40 JR0_INT06_DMA = $40 ;Floppy Disk Controller +=$80 JR0_INT07_TBD = $80 ; Mouse Interrupt (INT12 in SuperIO IOspace) + ; Register Block 1 +=$01 JR1_INT00_UART = $01 ;Keyboard Interrupt +=$02 JR1_INT01_COL0 = $02 ;TYVKY Collision TBD +=$04 JR1_INT02_COL1 = $04 ;TYVKY Collision TBD +=$08 JR1_INT03_COL2 = $08 ;TYVKY Collision TBD +=$10 JR1_INT04_RTC = $10 ;Serial Port 1 +=$20 JR1_INT05_VIA = $20 ;Midi Controller Interrupt +=$40 JR1_INT06_IEC = $40 ;Parallel Port +=$80 JR1_INT07_SDCARD = $80 ;SDCard Insert + + +;****** Processing input file: hardware/hardware.asm + + ; OpenKERNAL - a clean-room implementation of the C64's KERNAL ABI. + ; Copyright 2022 Jessie Oberreuter . + ; SPDX-License-Identifier: GPL-3.0-only + + hardware .namespace + .endn + + + +;****** Processing input file: hardware/i8042.asm + + ; OpenKERNAL - a clean-room implementation of the C64's KERNAL ABI. + ; Copyright 2022 Jessie Oberreuter . + ; SPDX-License-Identifier: GPL-3.0-only + + ; This file is from the w6502c TinyCore kernel by the same author. + + .cpu "w65c02" + + .namespace hardware + + i8042 .macro BASE = $D640 + .endm + .endn + + +;****** Processing input file: hardware/ps2.asm + + ; OpenKERNAL - a clean-room implementation of the C64's KERNAL ABI. + ; Copyright 2022 Jessie Oberreuter . + ; SPDX-License-Identifier: GPL-3.0-only + + ; This file borrows from the w6502c TinyCore kernel by the same author. + + .cpu "w65c02" + + .namespace hardware + + ps2 .namespace + + self .namespace + .virtual DevState +>0500 dummy .word ? ; TODO: Crazy? +>0502 upper .byte ? ; upper handler +>0503 irq .byte ? ; IRQ vector +>0504 port .byte ? ; PS2 port (0/1) +>0505 state .byte ? ; State machine state. +>0506 wait .byte ? ; starting tick +>0507 rx1 .byte ? ; least recent auto-detect byte +>0508 rx2 .byte ? ; middle auto-detect byte +>0509 rx3 .byte ? ; most recent auto-detect byte + .endv + .endn + + .section kernel + +.fc2a vectors +>fc2a c6 fc .word dev_data +>fc2c c4 fc .word dev_status +>fc2e c4 fc .word dev_fetch +>fc30 58 fc .word dev_open +>fc32 c4 fc .word dev_get +>fc34 c4 fc .word dev_set +>fc36 c4 fc .word dev_send +>fc38 be fc .word dev_close + +.fc3a init + ; A = upper, Y = IRQ + ; X <- initialized device, or carry set on error + +.fc3a 20 2a ed jsr $ed2a jsr kernel.device.alloc +.fc3d b0 18 bcs $fc57 bcs _out + +.fc3f 9d 02 05 sta $0502,x sta self.upper,x +.fc42 98 tya tya +.fc43 9d 03 05 sta $0503,x sta self.irq,x + +.fc46 38 sec sec +.fc47 e9 02 sbc #$02 sbc #irq.ps2_0 +.fc49 9d 04 05 sta $0504,x sta self.port,x + +.fc4c a9 2a lda #$2a lda #vectors +.fc52 85 a6 sta $a6 sta kernel.src+1 +.fc54 20 47 ed jsr $ed47 jsr kernel.device.install + +.fc57 60 rts _out rts + +.fc58 dev_open + +.fc58 9e 07 05 stz $0507,x stz self.rx1,x +.fc5b 9e 08 05 stz $0508,x stz self.rx2,x +.fc5e 9e 09 05 stz $0509,x stz self.rx3,x +.fc61 20 67 fd jsr $fd67 jsr hardware.kbd2.init + + ; Wait for reset success +.fc64 a9 00 lda #$00 lda #state.reset +.fc66 9e 05 05 stz $0505,x stz self.state,x + + ; Install our IRQ handler +.fc69 8a txa txa +.fc6a bc 03 05 ldy $0503,x ldy self.irq,x +.fc6d 20 d0 f5 jsr $f5d0 jsr irq.install + + ; Enable our IRQ +.fc70 bd 03 05 lda $0503,x lda self.irq,x +.fc73 20 d8 f5 jsr $f5d8 jsr irq.enable + +.fc76 da phx phx +.fc77 8a txa txa +.fc78 a8 tay tay + + ; Enable the port and interrupts +.fc79 5a phy phy +.fc7a b9 02 05 lda $0502,y lda self.upper,y +.fc7d aa tax tax +.fc7e b9 04 05 lda $0504,y lda self.port,y +.fc81 a8 tay tay +.fc82 20 0f ed jsr $ed0f jsr kernel.device.set +.fc85 7a ply ply +.fc86 b0 24 bcs $fcac bcs _out + + ; Send a reset +.fc88 a9 ff lda #$ff lda #$ff ; Reset +.fc8a 20 ae fc jsr $fcae jsr send_cmd +.fc8d b0 1d bcs $fcac bcs _out + + ; Wait for the state to change +.fc8f a5 a3 lda $a3 lda kernel.ticks +.fc91 99 06 05 sta $0506,y sta self.wait,y +.fc94 b9 05 05 lda $0505,y _loop lda self.state,y +.fc97 c9 00 cmp #$00 cmp #state.reset +.fc99 18 clc clc +.fc9a d0 10 bne $fcac bne _out +.fc9c 20 f8 e6 jsr $e6f8 jsr kernel.thread.yield +.fc9f a5 a3 lda $a3 lda kernel.ticks +.fca1 38 sec sec +.fca2 f9 06 05 sbc $0506,y sbc self.wait,y +.fca5 c9 b4 cmp #$b4 cmp #60*3 +.fca7 90 eb bcc $fc94 bcc _loop + + ; Ugh, no response ... just send some enables. +.fca9 20 f9 fc jsr $fcf9 jsr report + +.fcac fa plx _out plx +.fcad 60 rts rts + +.fcae send_cmd +.fcae 5a phy phy +.fcaf 48 pha pha + +.fcb0 b9 02 05 lda $0502,y lda self.upper,y +.fcb3 aa tax tax + +.fcb4 b9 04 05 lda $0504,y lda self.port,y +.fcb7 a8 tay tay + +.fcb8 68 pla pla +.fcb9 20 12 ed jsr $ed12 jsr kernel.device.send +.fcbc 7a ply ply + +.fcbd 60 rts rts + +.fcbe dev_close +.fcbe bd 03 05 lda $0503,x lda self.irq,x +.fcc1 4c fa f5 jmp $f5fa jmp irq.disable + +.fcc4 dev_get +.fcc4 dev_set +.fcc4 dev_send +.fcc4 dev_status +.fcc4 dev_fetch +.fcc4 18 clc clc +.fcc5 60 rts rts + +.fcc6 dev_data +.fcc6 8a txa txa +.fcc7 a8 tay tay + + ; Spin the IRQ counter + .if false + .endif +.fcc8 be 02 05 ldx $0502,y ldx self.upper,y +.fccb 20 0c ed jsr $ed0c jsr kernel.device.get + +.fcce be 05 05 ldx $0505,y ldx self.state,y +.fcd1 e0 0a cpx #$0a cpx #state.end +.fcd3 90 02 bcc $fcd7 bcc _ok +.fcd5 a2 00 ldx #$00 ldx #0 +.fcd7 _ok +.fcd7 7c da fc jmp ($fcda,x) jmp (_table,x) + +.fcda _table .dstruct state +>fcda e4 fc reset .word wait_reset +>fcdc 03 fd ack .word wait_ack +>fcde 12 fd data .word wait_data +>fce0 60 fd kbd2 .word state_kbd2 ; Mode-2 keyboard state machine +>fce2 66 fd mouse0 .word state_mouse0 ; Original 3-byte state machine +.fce4 end .ends + +.0000 state .struct +>0000 e4 fc reset .word wait_reset +>0002 03 fd ack .word wait_ack +>0004 12 fd data .word wait_data +>0006 60 fd kbd2 .word state_kbd2 ; Mode-2 keyboard state machine +>0008 66 fd mouse0 .word state_mouse0 ; Original 3-byte state machine +.000a end .ends + + + +.fce4 wait_reset + ; Whatever we got, advance +.fce4 4c f9 fc jmp $fcf9 jmp report + + +.fce7 c9 aa cmp #$aa cmp #$aa ; self test passed +.fce9 f0 0e beq $fcf9 beq report + +.fceb c9 fc cmp #$fc cmp #$fc +.fced f0 09 beq $fcf8 beq _done ; Reset failed, wait for user. +.fcef c9 fd cmp #$fd cmp #$fd +.fcf1 f0 05 beq $fcf8 beq _done ; Reset failed, wait for user. + +.fcf3 a9 ff lda #$ff lda #$ff ; reset +.fcf5 4c ae fc jmp $fcae jmp send_cmd ; Resend requested + +.fcf8 60 rts _done rts + +.fcf9 report +.fcf9 a9 04 lda #$04 lda #state.data +.fcfb 99 05 05 sta $0505,y sta self.state,y + + ; Request reporting +.fcfe a9 f4 lda #$f4 lda #$f4 ; Enable reporting +.fd00 4c ae fc jmp $fcae jmp send_cmd + +.fd03 wait_ack +.fd03 c9 fa cmp #$fa cmp #$fa +.fd05 f0 05 beq $fd0c beq _next + +.fd07 a9 d4 lda #$d4 lda #$d4 +.fd09 4c ae fc jmp $fcae jmp send_cmd + +.fd0c a9 04 lda #$04 _next lda #state.data +.fd0e 99 05 05 sta $0505,y sta self.state,y +.fd11 60 rts rts + +.fd12 wait_data +.fd12 80 03 bra $fd17 bra wait_auto + +.fd14 c9 aa cmp #$aa cmp #$aa + ;beq report ; Hot-plug event +.fd16 60 rts rts + + + +.fd17 wait_auto +.fd17 48 pha pha +.fd18 b9 08 05 lda $0508,y lda self.rx2,b,y +.fd1b 99 07 05 sta $0507,y sta self.rx1,b,y +.fd1e b9 09 05 lda $0509,y lda self.rx3,b,y +.fd21 99 08 05 sta $0508,y sta self.rx2,b,y +.fd24 68 pla pla +.fd25 99 09 05 sta $0509,y sta self.rx3,b,y + + ; Mode2 keyboard? +.fd28 b9 08 05 lda $0508,y _check2 lda self.rx2,b,y +.fd2b c9 f0 cmp #$f0 cmp #$f0 ; release +.fd2d d0 08 bne $fd37 bne _not2 +.fd2f b9 07 05 lda $0507,y lda self.rx1,b,y +.fd32 d9 09 05 cmp $0509,y cmp self.rx3,b,y +.fd35 f0 0b beq $fd42 beq _mode2 +.fd37 ea nop _not2 nop + + ; Mouse? +.fd38 b9 07 05 lda $0507,y lda self.rx1,b,y +.fd3b 29 cf and #$cf and #$cf +.fd3d 49 08 eor #$08 eor #$08 +.fd3f f0 19 beq $fd5a beq _mouse + +.fd41 60 rts _out rts + +.fd42 _mode2 + ; Switch to the mode2 machine. +.fd42 a9 06 lda #$06 lda #state.kbd2 +.fd44 99 05 05 sta $0505,y sta self.state,b,y + + ; Forward the last keypress to the mode2 machine. +.fd47 b9 07 05 lda $0507,y lda self.rx1,b,y +.fd4a 20 60 fd jsr $fd60 jsr state_kbd2 +.fd4d b9 08 05 lda $0508,y lda self.rx2,b,y +.fd50 20 60 fd jsr $fd60 jsr state_kbd2 +.fd53 b9 09 05 lda $0509,y lda self.rx3,b,y +.fd56 20 60 fd jsr $fd60 jsr state_kbd2 + +.fd59 60 rts rts + +.fd5a _mouse + ; Discard the detected movement; + ; switch to standard 3-byte mouse machine. +.fd5a a9 08 lda #$08 lda #state.mouse0 +.fd5c 99 05 05 sta $0505,y sta self.state,b,y +.fd5f 60 rts rts + +.fd60 state_kbd2 + ; Replace with a local state machine. +.fd60 5a phy phy +.fd61 20 a7 fd jsr $fda7 jsr hardware.kbd2.accept +.fd64 7a ply ply +.fd65 60 rts rts + +.fd66 state_mouse0 + ; Just drop the byte for now +.fd66 60 rts rts + + + .send + .endn + .endn + + +;****** Processing input file: hardware/ps2_kbd2.asm + + ; OpenKERNAL - a clean-room implementation of the C64's KERNAL ABI. + ; Copyright 2022 Jessie Oberreuter . + ; SPDX-License-Identifier: GPL-3.0-only + + ; This file is from the w6502c TinyCore kernel by the same author. + + .cpu "w65c02" + + .namespace hardware + + kbd2 .namespace + + .section kmem +>03ad e0 .byte ? +>03ae release .byte ? +>03af flags: .fill 16 + + .send + + .section kernel + +.fd67 init +.fd67 9c ad 03 stz $03ad stz e0 +.fd6a 9c ae 03 stz $03ae stz release +.fd6d da phx phx +.fd6e a2 00 ldx #$00 ldx #0 +.fd70 9e af 03 stz $03af,x _loop stz flags,x +.fd73 e8 inx inx +.fd74 e0 20 cpx #$20 cpx #32 +.fd76 d0 f8 bne $fd70 bne _loop +.fd78 fa plx plx +.fd79 18 clc clc +.fd7a 60 rts rts + +.fd7b search + ; Map keys prefixed with $e0. +.fd7b a2 00 ldx #$00 ldx #0 +.fd7d dd 8f fd cmp $fd8f,x _loop cmp _etab,x +.fd80 f0 09 beq $fd8b beq _found +.fd82 e8 inx inx +.fd83 e8 inx inx +.fd84 e0 18 cpx #$18 cpx #_end +.fd86 d0 f5 bne $fd7d bne _loop +.fd88 a9 00 lda #$00 lda #0 ; Ignore for the moment +.fd8a 60 rts rts + +.fd8b bd 90 fd lda $fd90,x _found lda _etab+1,x +.fd8e 60 rts rts + +.fd8f _etab +>fd8f 14 13 .byte $14, RCTRL +>fd91 6c 96 .byte $6c, HOME +>fd93 70 98 .byte $70, INS +>fd95 74 9c .byte $74, RIGHT +>fd97 11 15 .byte $11, RALT +>fd99 69 97 .byte $69, END +>fd9b 71 04 .byte $71, DEL +>fd9d 75 99 .byte $75, UP +>fd9f 7d 94 .byte $7d, PUP +>fda1 72 9a .byte $72, DOWN +>fda3 7a 95 .byte $7a, PDN +>fda5 6b 9b .byte $6b, LEFT +=24 _end = * - _etab + +.fda7 accept: +.fda7 c9 f0 cmp #$f0 cmp #$f0 ; Key release +.fda9 f0 35 beq $fde0 beq _release + +.fdab c9 e0 cmp #$e0 cmp #$e0 ; Media/extended prefix +.fdad f0 35 beq $fde4 beq _e0 + +.fdaf c9 e1 cmp #$e1 cmp #$e1 ; Pause... +.fdb1 f0 48 beq $fdfb beq _send + +.fdb3 c9 84 cmp #$84 cmp #$84 ; Apparently true +.fdb5 b0 1d bcs $fdd4 bcs _drop + +.fdb7 ae ad 03 ldx $03ad ldx e0 +.fdba f0 05 beq $fdc1 beq _std +.fdbc 20 7b fd jsr $fd7b jsr search +.fdbf 80 04 bra $fdc5 bra _code +.fdc1 _std +.fdc1 aa tax tax +.fdc2 bd 82 fe lda $fe82,x lda keymap,x + +.fdc5 ae ae 03 ldx $03ae _code ldx release +.fdc8 f0 1e beq $fde8 beq _press + + ; Clear mode flags +.fdca aa tax tax +.fdcb 29 f0 and #$f0 and #$f0 +.fdcd c9 10 cmp #$10 cmp #16 +.fdcf d0 03 bne $fdd4 bne _drop +.fdd1 9e 9f 03 stz $039f,x stz flags-16,x + +.fdd4 9c ad 03 stz $03ad _drop stz e0 +.fdd7 9c ae 03 stz $03ae stz release +.fdda 60 rts rts + +.fddb 20 7b fd jsr $fd7b _search jsr search +.fdde 80 e5 bra $fdc5 bra _code + + +.fde0 8d ae 03 sta $03ae _release sta release +.fde3 60 rts rts + +.fde4 8d ad 03 sta $03ad _e0 sta e0,b +.fde7 60 rts rts + +.fde8 20 d4 fd jsr $fdd4 _press jsr _drop +.fdeb aa tax tax +.fdec 29 f0 and #$f0 and #$f0 +.fdee c9 10 cmp #$10 cmp #16 +.fdf0 d0 04 bne $fdf6 bne _key +.fdf2 9d 9f 03 sta $039f,x sta flags-16,x +.fdf5 60 rts rts + +.fdf6 8a txa _key txa +.fdf7 c9 00 cmp #$00 cmp #0 +.fdf9 f0 06 beq $fe01 beq _end +.fdfb 20 02 fe jsr $fe02 _send jsr _flags + + .if false + .endif +.fdfe 20 b1 ec jsr $ecb1 jsr kernel.keyboard.enque + +.fe01 60 rts _end rts + +.fe02 48 pha _flags pha +.fe03 a9 00 lda #$00 lda #0 +.fe05 a2 00 ldx #$00 ldx #0 +.fe07 bc af 03 ldy $03af,x _loop ldy flags,x +.fe0a f0 03 beq $fe0f beq _next +.fe0c 1d 1f fe ora $fe1f,x ora _meta,x +.fe0f e8 inx _next inx +.fe10 e0 09 cpx #$09 cpx #9 +.fe12 d0 f3 bne $fe07 bne _loop +.fe14 ba tsx tsx +.fe15 89 02 bit #$02 bit #2 +.fe17 d0 0f bne $fe28 bne _ctrl +.fe19 89 01 bit #$01 bit #1 +.fe1b d0 15 bne $fe32 bne _shift +.fe1d 68 pla _out pla +.fe1e 60 rts rts +>fe1f 01 01 02 02 04 04 08 08 _meta .byte 1,1,2,2,4,4,8,8,1 +>fe27 01 +.fe28 bd 01 01 lda $0101,x _ctrl lda Stack+1,x +.fe2b 29 1f and #$1f and #$1f +.fe2d 9d 01 01 sta $0101,x sta Stack+1,x +.fe30 80 eb bra $fe1d bra _out +.fe32 bd 01 01 lda $0101,x _shift lda Stack+1,x +.fe35 20 3d fe jsr $fe3d jsr shift +.fe38 9d 01 01 sta $0101,x sta Stack+1,x +.fe3b 80 e0 bra $fe1d bra _out + +.fe3d shift +.fe3d c9 61 cmp #$61 cmp #'a' +.fe3f 90 07 bcc $fe48 bcc _find +.fe41 c9 7b cmp #$7b cmp #'z'+1 +.fe43 b0 03 bcs $fe48 bcs _find +.fe45 49 20 eor #$20 eor #$20 +.fe47 60 rts rts +.fe48 _find +.fe48 a0 00 ldy #$00 ldy #0 +.fe4a d9 5a fe cmp $fe5a,y _loop cmp _map,y +.fe4d f0 07 beq $fe56 beq _found +.fe4f c8 iny iny +.fe50 c8 iny iny +.fe51 c0 28 cpy #$28 cpy #_end +.fe53 d0 f5 bne $fe4a bne _loop +.fe55 60 rts rts +.fe56 b9 5b fe lda $fe5b,y _found lda _map+1,y +.fe59 60 rts rts +.fe5a _map +>fe5a 31 21 .byte '1', '!' +>fe5c 32 40 .byte '2', '@' +>fe5e 33 23 .byte '3', '#' +>fe60 34 24 .byte '4', '$' +>fe62 35 25 .byte '5', '%' +>fe64 36 5e .byte '6', '^' +>fe66 37 26 .byte '7', '&' +>fe68 38 2a .byte '8', '*' +>fe6a 39 28 .byte '9', '(' +>fe6c 30 29 .byte '0', ')' +>fe6e 2d 5f .byte '-', '_' +>fe70 3d 2b .byte '=', '+' + +>fe72 5b 7b .byte '[', '{' +>fe74 5d 7d .byte ']', '}' +>fe76 5c 7c .byte $5c, '|' + +>fe78 3b 3a .byte ';', ':' +>fe7a 27 22 .byte $27, $22 + +>fe7c 2c 3c .byte ',', '<' +>fe7e 2e 3e .byte '.', '>' +>fe80 2f 3f .byte '/', '?' + +=40 _end = * - _map + + + +.fe82 keymap: + +>fe82 00 89 00 85 83 81 82 8c .byte 0, F9, 0, F5, F3, F1, F2, F12 +>fe8a 00 8a 88 86 84 09 60 00 .byte 0, F10, F8, F6, F4, 9, '`', 0 +>fe92 00 14 10 00 12 71 31 00 .byte 0, LALT, LSHIFT, 0, LCTRL, 'q', '1', 0 +>fe9a 00 00 7a 73 61 77 32 00 .byte 0, 0, 'z', 's', 'a', 'w', '2', 0 +>fea2 00 63 78 64 65 34 33 00 .byte 0, 'c', 'x', 'd', 'e', '4', '3', 0 +>feaa 00 20 76 66 74 72 35 00 .byte 0, ' ', 'v', 'f', 't', 'r', '5', 0 +>feb2 00 6e 62 68 67 79 36 00 .byte 0, 'n', 'b', 'h', 'g', 'y', '6', 0 +>feba 00 00 6d 6a 75 37 38 00 .byte 0, 0, 'm', 'j', 'u', '7', '8', 0 +>fec2 00 2c 6b 69 6f 30 39 00 .byte 0, ',', 'k', 'i', 'o', '0', '9', 0 +>feca 00 2e 2f 6c 3b 70 2d 00 .byte 0, '.', '/', 'l', ';', 'p', '-', 0 +>fed2 00 00 27 00 5b 3d 00 00 .byte 0, 0, "'", 0, '[', '=', 0, 0 +>feda 18 11 0d 5d 00 5c 00 00 .byte CAPS, RSHIFT, RETURN, ']', 0, '\', 0, 0 +>fee2 00 00 00 00 00 00 08 00 .byte 0, 0, 0, 0, 0, 0, BKSP, 0 +>feea 00 a1 00 a4 a7 00 00 00 .byte 0, K1, 0, K4, K7, 0, 0, 0 +>fef2 a0 ae a2 a5 a6 a8 1b b0 .byte K0, KPOINT, K2, K5, K6, K8, ESC, NUM +>fefa 8b aa a3 ab ac a9 9d 00 .byte F11, KPLUS, K3, KMINUS, KTIMES, K9, SCROLL, 0 +>ff02 00 00 00 87 9e 00 00 00 .byte 0, 0, 0, F7, SYSREQ, 0, 0, 0, 0 +>ff0a 00 + + .send + .endn + .endn + + +;****** Processing input file: hardware/keys.asm + + ; OpenKERNAL - a clean-room implementation of the C64's KERNAL ABI. + ; Copyright 2022 Jessie Oberreuter . + ; SPDX-License-Identifier: GPL-3.0-only + + ; This file is from the w6502c TinyCore kernel by the same author. + +=16 LSHIFT = 16 +=17 RSHIFT = 17 +=18 LCTRL = 18 +=19 RCTRL = 19 +=20 LALT = 20 +=21 RALT = 21 +=22 LMETA = 22 +=23 RMETA = 23 +=24 CAPS = 24 + +=$e1 PAUSE = $e1 +=129 F1 = 129 +=130 F2 = 130 +=131 F3 = 131 +=132 F4 = 132 +=133 F5 = 133 +=134 F6 = 134 +=135 F7 = 135 +=136 F8 = 136 +=137 F9 = 137 +=138 F10 = 138 +=139 F11 = 139 +=140 F12 = 140 + +=148 PUP = 148 +=149 PDN = 149 +=150 HOME = 150 +=151 END = 151 +=152 INS = 152 +=153 UP = 153 +=154 DOWN = 154 +=155 LEFT = 155 +=156 RIGHT = 156 +=157 SCROLL = 157 +=158 SYSREQ = 158 +=159 BREAK = 159 + +=160 K0 = 160 +=161 K1 = 161 +=162 K2 = 162 +=163 K3 = 163 +=164 K4 = 164 +=165 K5 = 165 +=166 K6 = 166 +=167 K7 = 167 +=168 K8 = 168 +=169 K9 = 169 +=170 KPLUS = 170 +=171 KMINUS = 171 +=172 KTIMES = 172 +=173 KDIV = 173 +=174 KPOINT = 174 +=175 KENTER = 175 +=176 NUM = 176 + +=177 POWER = 177 +=178 SLEEP = 178 +=179 WAKE = 179 +=180 PRTSCR = 180 +=181 MENU = 181 + +=4 DEL = 4 +=13 RETURN = 13 +=27 ESC = 27 +=9 TAB = 9 +=8 BKSP = 8 + + + +;****** End of listing diff --git a/Release Notes.txt b/Release Notes.txt index 734894e..b76f08d 100644 --- a/Release Notes.txt +++ b/Release Notes.txt @@ -1,3 +1,12 @@ +Release 0.6.0.2 +--------------- +Fixed CPU reading incorrect page when MMU is present in F256Jr. +Fixed LUT editing issue. +Fixed Tileset stride issue. +Removed MultimediaTimer and replaced with a native C# HiResTimer. +Added sprite functionality for the F256Jr. +In the Uploader window, when in F256Jr mode, the buffer size is 2K. + Release 0.6.0.1 --------------- Implemented tiles for F256Jr. diff --git a/bin/Release/FoenixIDE.exe b/bin/Release/FoenixIDE.exe index 246b974..3b5803d 100644 Binary files a/bin/Release/FoenixIDE.exe and b/bin/Release/FoenixIDE.exe differ