diff options
| author | Melodi <62381002+Melodi17@users.noreply.github.com> | 2026-02-26 04:19:20 +1000 |
|---|---|---|
| committer | Melodi <62381002+Melodi17@users.noreply.github.com> | 2026-02-26 04:19:20 +1000 |
| commit | 1e5c56c33291dad6f603a98b555194f3af252805 (patch) | |
| tree | 862cc486359eaf48fa0e5d11d364fe56751da18c /Program.cs | |
Initial commit
Diffstat (limited to 'Program.cs')
| -rw-r--r-- | Program.cs | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..800ee12 --- /dev/null +++ b/Program.cs @@ -0,0 +1,195 @@ +namespace pgch8; + +using System.Text; +using Npgsql; + +class Program +{ + private static NpgsqlConnection _conn; + private static Screen _screen; + + static void Main(string[] args) + { + CreateConnection(); + Program.Reset(); + + CreateScreen(); + WriteRom("/Users/melodidey/Source/csharp/pgch8/test_opcode.ch8"); + WriteFont([ + 0xF0, 0x90, 0x90, 0x90, 0xF0, // 0 + 0x20, 0x60, 0x20, 0x20, 0x70, // 1 + 0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2 + 0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3 + 0x90, 0x90, 0xF0, 0x10, 0x10, // 4 + 0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5 + 0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6 + 0xF0, 0x10, 0x20, 0x40, 0x40, // 7 + 0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8 + 0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9 + 0xF0, 0x90, 0xF0, 0x90, 0x90, // A + 0xE0, 0x90, 0xE0, 0x90, 0xE0, // B + 0xF0, 0x80, 0x80, 0x80, 0xF0, // C + 0xE0, 0x90, 0x90, 0x90, 0xE0, // D + 0xF0, 0x80, 0xF0, 0x80, 0xF0, // E + 0xF0, 0x80, 0xF0, 0x80, 0x80 // F + ]); + + while (true) + { + Program.Clock(); + if (Program.IsScreenDirty()) + { + _screen.Pixels = Program.GetScreenPixels(); + _screen.Render(); + Program.MarkScreenClean(); + } + + Thread.Sleep(1000 / 60); + } + } + + private static void Reset() + { + Program.Execute("select private.reset();"); + } + + private static void Clock() + { + Program.Execute("select private.clock();"); + } + + private static bool IsScreenDirty() + { + return Program.QuerySingle<bool>("select private.is_screen_dirty();"); + } + + private static void MarkScreenClean() + { + Program.Execute("select private.mark_screen_clean();"); + } + + private static bool[] GetScreenPixels() + { + return Program.Query( + "select value from private.display order by i;", + reader => + { + List<bool> pixels = new(); + while (reader.Read()) + { + pixels.Add(reader.GetBoolean(0)); + } + return pixels.ToArray(); + }); + } + + private static void CreateConnection() + { + Program._conn = new("Host=localhost;Username=melodidey;Database=emulator"); + Program._conn.Open(); + } + + private static void CreateScreen() + { + int screenWidth = QuerySingle<int>("select value from private.constants where label = 'Screen Width';"); + int screenHeight = QuerySingle<int>("select value from private.constants where label = 'Screen Height';"); + + Program._screen = new Screen(screenWidth, screenHeight); + } + + private static void WriteRom(string path) + { + byte[] rom = File.ReadAllBytes(path); + + int romStart = QuerySingle<int>( + "select value_word from private.constants where label = 'Program Start';" + ); + + for (int i = 0; i < rom.Length; i++) + { + Execute( + "update private.memory set value = @p1 where address = @p0;", + romStart + i, + rom[i] + ); + } + } + + private static void WriteFont(byte[] font) + { + int fontStart = QuerySingle<int>( + "select value_word from private.constants where label = 'Font Start';" + ); + + for (int i = 0; i < font.Length; i++) + { + Execute( + "update private.memory set value = @p1 where address = @p0;", + fontStart + i, + font[i] + ); + } + } + + static void Execute(string query, params object[] parameters) + { + using var cmd = new NpgsqlCommand(query, Program._conn); + for (int i = 0; i < parameters.Length; i++) + { + cmd.Parameters.AddWithValue($"@p{i}", parameters[i]); + } + cmd.ExecuteNonQuery(); + } + + static T Query<T>(string query, Func<NpgsqlDataReader, T> map) + { + using var cmd = new NpgsqlCommand(query, Program._conn); + using var reader = cmd.ExecuteReader(); + return map(reader); + } + + static T QuerySingle<T>(string query) + { + try + { + return Query(query, reader => + { + reader.Read(); + return reader.GetFieldValue<T>(0); + }); + } + catch (Exception ex) + { + Console.WriteLine($"Error executing query '{query}': {ex.Message}"); + throw; + } + } +} + +class Screen +{ + public int Width { get; set; } + public int Height { get; set; } + public bool[] Pixels { get; set; } + + public Screen(int width, int height) + { + Width = width; + Height = height; + Pixels = new bool[width * height]; + } + + public void Render() + { + StringBuilder sb = new(); + for (int i = 0; i < Pixels.Length; i++) + { + sb.Append(Pixels[i] ? "#" : " "); + if ((i + 1) % Width == 0) + sb.AppendLine(); + } + + Console.Clear(); + Console.WriteLine(sb.ToString()); + } +}
\ No newline at end of file |
