https://github.com/jonathanpeppers/dotnes Skip to content Navigation Menu Toggle navigation Sign in * Product + Actions Automate any workflow + Packages Host and manage packages + Security Find and fix vulnerabilities + Codespaces Instant dev environments + Copilot Write better code with AI + Code review Manage code changes + Issues Plan and track work + Discussions Collaborate outside of code Explore + All features + Documentation + GitHub Skills + Blog * Solutions For + Enterprise + Teams + Startups + Education By Solution + CI/CD & Automation + DevOps + DevSecOps Resources + Learning Pathways + White papers, Ebooks, Webinars + Customer Stories + Partners * Open Source + GitHub Sponsors Fund open source developers + The ReadME Project GitHub community articles Repositories + Topics + Trending + Collections * Pricing Search or jump to... Search code, repositories, users, issues, pull requests... Search [ ] Clear Search syntax tips Provide feedback We read every piece of feedback, and take your input very seriously. [ ] [ ] Include my email address so I can be contacted Cancel Submit feedback Saved searches Use saved searches to filter your results more quickly Name [ ] Query [ ] To see all available qualifiers, see our documentation. Cancel Create saved search Sign in Sign up You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session. Dismiss alert {{ message }} jonathanpeppers / dotnes Public * Notifications * Fork 6 * Star 245 * .NET for the NES game console License MIT license 245 stars 6 forks Branches Tags Activity Star Notifications * Code * Issues 2 * Pull requests 1 * Actions * Projects 0 * Security * Insights Additional navigation options * Code * Issues * Pull requests * Actions * Projects * Security * Insights jonathanpeppers/dotnes This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository. main BranchesTags Go to file Code Folders and files Name Name Last commit Last commit message date Latest commit History 130 Commits .github/workflows .github/workflows .vscode .vscode assets assets samples samples src src .editorconfig .editorconfig .gitattributes .gitattributes .gitignore .gitignore Directory.Build.props Directory.Build.props LICENSE LICENSE README.md README.md dotnes.sln dotnes.sln global.json global.json View all files Repository files navigation * README * MIT license .NES ("dot" NES) dot NES logo .NET for the NES game console! Gif of NES Emulator launching from VS Code Getting Started Simply install the template: dotnet new install dotnes.templates Create a project: dotnet new nes Or use the project template in Visual Studio: Screenshot of the NES project template in Visual Studio Build and run it as you would a console app: dotnet run Of course, you can also just open the project in Visual Studio and hit F5. Note that Ctrl+F5 currently works better in C# Dev Kit in VS Code. Check out the video for a full demo: Check out the video Anatomy of an NES application "Hello World" looks something like: // set palette colors pal_col(0, 0x02); // set screen to dark blue pal_col(1, 0x14); // fuchsia pal_col(2, 0x20); // grey pal_col(3, 0x30); // white // write text to name table vram_adr(NTADR_A(2, 2)); // set address vram_write("Hello, world!"); // write bytes to video RAM // enable PPU rendering (turn on screen) ppu_on_all(); // infinite loop while (true) ; This looks very much like "Hello World" in C, taking advantage of the latest C# features in 2023. By default the APIs like pal_col, etc. are provided by an implicit global using static NESLib; and all code is written within a single Program.cs. Additionally, a chr_generic.s file is included as your game's "artwork" (lol?): .segment "CHARS" .byte $00,$00,$00,$00,$00,$00,$00,$00 ... .byte $B4,$8C,$FC,$3C,$98,$C0,$00,$00 ;; This table of data is used to render sprites, text, etc. Scope The types of things I wanted to get working initially: * An object model for writing NES binaries * Building a project should produce a *.nes binary, that is byte-for-byte identical to a program written in C. * "Hello World" runs * Byte arrays, and a more advanced sample like attributetable run * Local variables work in some form * Project template, MSBuild support, IDE support Down the road, I might think about support for: * Methods * Structs * Multiple files * Some subset of useful BCL methods How it works For lack of a better word, .NES is a "transpiler" that takes MSIL and transforms it directly into a working 6502 microprocessor binary that can run in your favorite NES emulator. If you think about .NET's Just-In-Time (JIT) compiler or the various an Ahead-Of-Time (AOT) compilers, .NES is doing something similiar: taking MSIL and turning it into runnable machine code. To understand further, let's look at the MSIL of a pal_col method call: // pal_col((byte)0, (byte)2); IL_0000: ldc.i4.0 IL_0001: ldc.i4.2 IL_0002: call void [neslib]NES.NESLib::pal_col(uint8, uint8) In 6502 assembly, this would look something like: A900 LDA #$00 20A285 JSR pusha A902 LDA #$02 203E82 JSR _pal_col You can see how one might envision using System.Reflection.Metadata to iterate over the contents of a .NET assembly and generate 6502 instructions -- that's how this whole idea was born! Note that the method NESLib.pal_col() has no actual C# implementation. In fact! there is only a reference assembly even shipped in .NES: > 7z l dotnes.0.1.1-alpha.nupkg Date Time Attr Size Compressed Name ------------------- ----- ------------ ------------ ------------------------ 2023-09-14 14:37:38 ..... 8192 3169 ref\net8.0\neslib.dll If you decompile neslib.dll, no code is inside: // Warning! This assembly is marked as a 'reference assembly', which means that it only contains metadata and no executable code. // neslib, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null // NES.NESLib public static void pal_col(byte index, byte color) => throw null; When generating *.nes binaries, .NES simply does a lookup for pal_col to "jump" to the appropriate subroutine to call it. .NES also emits the assembly instructions for the actual pal_col subroutine, a code snippet of the implementation: /* * 823E 8517 STA TEMP ; _pal_col * 8240 209285 JSR popa * 8243 291F AND #$1F * 8245 AA TAX * 8246 A517 LDA TEMP * 8248 9DC001 STA $01C0,x * 824B E607 INC PAL_UPDATE * 824D 60 RTS */ Write(NESInstruction.STA_zpg, TEMP); Write(NESInstruction.JSR, popa.GetAddressAfterMain(sizeOfMain)); Write(NESInstruction.AND, 0x1F); Write(NESInstruction.TAX_impl); Write(NESInstruction.LDA_zpg, TEMP); Write(NESInstruction.STA_abs_X, PAL_BUF); Write(NESInstruction.INC_zpg, PAL_UPDATE); Write(NESInstruction.RTS_impl); Limitations This is a hobby project, so only around 5 C# programs are known to work. But to get an idea of what is not available: * No runtime * No BCL * No objects or GC * No debugger * Strings are ASCII What we do have is a way to express an NES program in a single Program.cs. Links To learn more about NES development, I found the following useful: * 8bitworkshop * NES 6502 Programming Tutorial * INES File Format * 6502 Instruction Set * HxD Hex Editor ANESE License I needed a simple, small NES emulator to redistribute with .NES that runs on Mac and Windows. Special thanks to @daniel5151 and ANESE. This is the default NES emulator used in the dotnet.anese package, license here. About .NET for the NES game console Topics csharp dotnet emulation nes hacktoberfest Resources Readme License MIT license Activity Stars 245 stars Watchers 8 watching Forks 6 forks Report repository Releases 2 0.1.1-alpha Latest May 21, 2024 + 1 release Languages * C# 90.7% * Assembly 9.3% Footer (c) 2024 GitHub, Inc. Footer navigation * Terms * Privacy * Security * Status * Docs * Contact * Manage cookies * Do not share my personal information You can't perform that action at this time.