You are browsing as a guest. Sign up (or log in) to start making projects!

Rust 6502

  • 44 Devlogs
  • 36 Total hours

A MOS-6502 Emulator written in Rust

Ship #1

=== Rust 6502 ===

A legendary 8-bit CPU right in your terminal! 🦀 ᕙ( •̀ ᗜ •́ )ᕗ

== What did you make ? ==

I built a fully functional emulator for the MOS 6502 (the microprocessor that powered the Apple II, Commodre 64, and the NES) from scratch using Rust !
Instead of a standard graphical window, I built a Terminal User Interface (TUI) using Ratatui.

Here is what's inside:
- Full CPU Emulation: Execute 6502 machine code with live register (AC, XR, YR, SP) and status flag tracking
- Virtual Screen: A 32x32 memory-mapped display ($0200-$05FF) rendered right in the terminal using Unicode Half-Block and a custom 16-color palette
- Live Disassembler & Hex Viewer: Watch the RAM change in real-time and see the raw binary machine code translated back into readable assembly instructions on the fly
- Built-in File Browser: A visual menu with Nerd Font icons to navigate your system and load compiled .bin ROMs
- Available on crates.io : You can download it via Cargo

== What was challenging ? ==

- The Disassembler: Writing a disassembler that parses raw .bin files is tricky because they don't have headers. I ran into a massive issue where my image data (using the color byte $0A) was being read by the disassembler as infinite ASL A (Shift Left) instructions! I had to engineer a way for the disassembler to properly halt when it hit a BRK instruction so it wouldn't try to execute my pixel art.

- Terminal UI Architecture: Designing a dashboard (hex grids, scrolling stacks, changing colors) required a really solid state-management architecture to keep the UI smooth and responsive while the CPU loop spins at thousands of instructions per second.

== What are you proud of ? ==

I am proud of using this project to learn Rust in a fun way!

ദ്ദി(˵ •̀ ᴗ - ˵ ) ✧

I'm also really proud that it's officially published on crates.io, meaning anyone can install and run my emulator with a single command

== What should people know so they can test your project ? ==

Note: A Nerd Font is recommended in your terminal emulator for a proper rendering of the UI icons on the Home page

How to test:

- Install the emulator directly from crates.io by running:
cargo install rust6502

- Download all the .bin files on the GitHub Releases page.

- Launch the emulator by running rust6502 and use the built-in Home menu to select one of the demo .bin files!

== Things to try ==

- Load hackclub_logo_demo.bin to see the terminal render a 32x32 pixel art logo using 6502 assembly

- Load rainbow_demo.bin to watch a shifting color gradient animation directly manipulating video memory.

- Load helloworld_demo.bin to watch a centered Hello world message

- The Debugger: go to the Settings menu inside the TUI and slow down the CPU speed. Then watch the Memory Viewer and Disassembler track exactly what the code is doing in real-time!

  • 44 devlogs
  • 36h
Try project → See source code →
Open comments for this post

16m 45s logged

Last devlogs before Ship #1 :yay:
Wow 37h of work.

I have made an Asciinema video, Youtube video and update the README.md

Wish me luck !

0
0
8
Open comments for this post

46m 52s logged

I have added a new program called HackClub Logo :yay:
First, I have draw the hackclub logo in aseprite with a 32x32 pixel file using my custom color palette.

Second, I have created a simple python script who take a .png in input and output ASM raw data for the image (using my color palette).

Third, I have create a simple ASM program to print the logo on the screen !

0
0
17
Open comments for this post

36m 24s logged

Little bug fix: Now when we select a file in the Home File Selector the filename appear in the Opcode container.
I have also reorganize the tui.rs code !

0
0
6
Open comments for this post

21m 39s logged

WOW already 30 hours ?! 😅
I now have added the home logo ! I also changed the step for the speed selection on Home Menu from 500 to 100 for each step

0
0
6
Open comments for this post

2h 4m 31s logged

Wow that was damn hard 😭. But the Home Menu is finally here 🎉. There is the logo (might change). The select file container with full navigation (folder, parent directory, file), Icon (require a Nerd Font) and Colors. The selected file path update in real time with the absolute path of the file. The start address automatically change if the file selected is a demo file (end with “_demo.bin”) to $C000. The start address it editable with Alpha numeric character (hexadecimal). And the emulation speed work ! There is control on the footer bar.

0
0
4
Open comments for this post

1h 13m 18s logged

New demo program… HelloWorld_demo !
Print Hello World ! centered on the screen all in pure 6502 Assembly. I also modified the way the disassembler work, now even if there is a BRK it will continue to read the file until the end. The ASM part was really really haaarrddd.

0
0
102
Open comments for this post

32m 58s logged

I have update the color from word to RGB value so if a different terminal theme is applied the color are the same. I also added a footer bar with the keybinds.

0
0
4
Open comments for this post

1h 24m 59s logged

New panel 🥁🥁🥁…. the ✨ SETTINGS ✨ !
In this panel there is a smaller version of the Logo and the settings to modify the speed of the CPU. There is also the link to the github repo and stardance project

0
0
3
Open comments for this post

17m 9s logged

Now the name of the file currently running is in the title. I also finished the rainbow program to fill the whole screen.

0
0
3
Open comments for this post

1h 42m 43s logged

New feature 🥁🥁🥁 ✨ THE SCREEN ✨ This was very very hard. The screen use the Unicode half-block character “▀”, to write to the screen you just need to send value like this :

LDA #$02      ; load "02" into the accumulator
STA $0200     ; store it at memory address $0200 (the 1st pixel)

Here the 02 is the color RED.
Here is the color palette:

fn palette_color(index: u8) -> Color {
    match index & 0x0F {
        0 => Color::Black,
        1 => Color::White,
        2 => Color::Red,
        3 => Color::Cyan,
        4 => Color::Magenta,
        5 => Color::Green,
        6 => Color::Blue,
        7 => Color::Yellow,
        8 => Color::Rgb(255, 165, 0), // Orange
        9 => Color::Rgb(153, 76, 0), // Brown
        10 => Color::DarkGray,
        11 => Color::Gray,
        12 => Color::LightRed,
        13 => Color::LightBlue,
        14 => Color::LightGreen,
        _ => Color::Reset, // 15 transparent
    }
}

The color may vary between terminal theme.

I also had created an ASM program to print a rainbow on the 1st quarter of the screen.

I also added the feature that when a BRK instruction is hit the program turn to HALT mode (in the UI).

I also added the indentation system to BEQ, BNE, BCC, BCS, BMI, BPL, BVC, BVS.

I also added a new way of calculating the speed of the program.

0
0
4
Open comments for this post

24m 16s logged

Choosing between a variety of logo (2 first screen shot are in Apple Terminal the last is in ghostty with a Catpuccin Mocha theme)

0
0
30
Open comments for this post

54m 51s logged

I have added a top bar in the memory container with the last part of the address (to be more easy to read).

I also fixed all the scroll bar from scrolling outside the container and just see nothings

0
0
10
Open comments for this post

22m 51s logged

I have fixed the cursor in the Stack Container to scroll automaticly when needed and when running. I also optimised the code !

0
0
5
Open comments for this post

1h 5m 44s logged

A lot has been going on :yay: ! I have added the Memory Viewer, Scroll bar to the Stack Viewer and Memory Viewer (work with the 🥁…. SCROLL WHEEL !). I also reduce the space taken by the opcode list so we can see the memory viewer !

0
0
4
Open comments for this post

27m 49s logged

I have added a Stack Viewer on the left ! The container scroll it self when the “cursor”/current position of the Stack Pointer (SP). I also have fix the text for the SP in the register container

0
0
38
Open comments for this post

1h 15m 49s logged

The UI is going forward one step after another ! :yay:

I have changed a some little like the place where is the Flag Container, now it’s on the left side.

And I also have added a LOT a things like:

  • Register Container (under the Flag Container)
  • Now when there is a JMP (or any type or jump like RST, etc…) the code indent it self
  • Up and Down key move the cursor 🥁…. ✨UP & DOWN ✨
  • New color for the ADDR in the Opcode container

Things I have removed:

  • BYTES section in the Opcode container because I don’t think it’s really useful
0
0
9
Open comments for this post

1h 6m 1s logged

I am now making the TUI part of this emulator ! I am using Ratatui to make the TUI. This mean I have to change all the printing part of my existing program

0
0
8
Open comments for this post

1h 2m 21s logged

I’m being closer and closer of getting all opcode and all Addressing mode implemented :yay:

Here are the list of opcode I have implemented and there Addressing Mode:

  • ADC
    • Zeropage X
    • Absolute
    • Absolute X
    • Absolute Y
    • Indirect X
    • Indirect Y
  • AND
    • Zeropage
    • Zeropage X
    • Absolute
    • Absolute X
    • Absolute Y
    • Indirect X
    • Indirect Y
  • CMP
    • Zeropage
    • Zeropage X
    • Absolute
    • Absolute X
    • Absolute Y
    • Indirect X
    • Indirect Y
  • EOR
    • Zeropage
    • Zeropage X
    • Absolute
    • Absolute X
    • Absolute Y
    • Indirect X
    • Indirect Y

I also fixed the CLD instruction. I was doing a :

cpu.sr |= !CPU::DECIMAL_FLAG;

but the right one was this:

cpu.sr &= !CPU::DECIMAL_FLAG;
0
0
3
Open comments for this post

41m 48s logged

I’ve just passed 40min to fix an interruption problem to final look back and see that my original code what working perfectly fine 😭 . I’ve also change my build tools to ca65 + ld65

0
0
7
Open comments for this post

36m 54s logged

New opcode :pcb:

  • TXS (transfer X to stack pointer)
  • TSX (transfer stack pointer to X)
  • ldx_absolute_Y
  • lda_indirect_x
  • lda_indirect_y
  • ldx_zeropage_y

New Addressing Mode:

  • AbsoluteY
  • ZeroPageY
  • IndirectX
  • IndirectY
0
0
3
Open comments for this post

27m 49s logged

✨ NEW OPCODE ✨ :yay: :

  • PHP (Push Processor Status: push current value of all the flag to the stack)
  • PLP (Pull Processor Status: pull current value of all the flag to the stack)

But I have also add a memory dump with page (at the end of a program) to debug ! (1st screenshot) and i also add a fixed (address) memory viewer when running (2nd screenshot)

0
0
14
Open comments for this post

46m 11s logged

Now there is a pop_stack function who return the top value of the stack (Last In First Out).
I’ve also added those opcode :

  • JSR
  • RST

And made this test code :

0
0
6
Open comments for this post

1h 43m 50s logged

I’ve done a LOT of work.
Added Opcodes:

  • BEQ
  • BNE
  • SBC Immediate + Zeropage

I’ve also done a lot of refractorisation. Code before :

match opcode {
          0x18 => {
                    self.sr &= !CPU::CARRY_FLAG;                                      

                    self.set_instr(format!("{:02X}", opcode), "CLC".to_string(), 2);
          },
          // ... 
}

VS now :


match opcode {
          0x18 => self.clc(opcode),
          // ... 
}

So now every opcode have his own function !

0
0
4
Open comments for this post

31m 11s logged

I’ve added those instruction:

  • ADC (Add with Carry)
  • CLC (Clear Carry Flag)
  • SEC (Set Carry Flag)

I’ve also made this little ASM 6502 program to test those opcode

.org $8000
START:
    SEC         ; to test CLC
    LDA #$FF    ; A = 255
    CLC         ; Clear Carry Flag before addition
    ADC #$02    ; 255 + 2 = 1, Carry is now 1 (0x01FF +                   0x0002 = 0x0201)
    STA $20     ; Store Low Byte result (01) at $20
    LDA #$00    ; Load 0 for the high byte
    ADC #$00    ; 0 + 0 + 1 (Carry from previous instruction) = 1 
    STA $21     ; Store High Byte result (01) at $21
    ; SEC use
    SEC         ; Carry = 1
    LDA #$01    ; A = 1
    ADC #$00    ; 1 + 0 + 1 (Carry) = 2
    BRK

And it work just fine !

0
0
3
Open comments for this post

51m 42s logged

I’ve added a bunch of opcode like : STA, STX, STY (Zero Page, Absolute) LDX, LDY (Immediate, Zero Page, Absolute) JMP (Absolute), JMP (Indirect) (the screen shot is a new program that i’ve made and test on virtual 6502 and my project)

0
0
2
Open comments for this post

2h 3m 13s logged

Hi ! Right now in my project I have added :

  • Bus with ram

    • read & write function
    • load from file function
  • CPU

    • All registry (a, x, y, sp, pc, sr)
    • reset cpu function
    • update Z & N flag function
    • clock_tick with those opcode in it : BRK; DEY; TXA; TYA; TAY; LDA; TAX; INY; DEX; INX; NOP

(1st screenshot is official emulator 2nd is mine)

0
0
5

Delete project?

Are you sure you want to permanently delete this project? This action cannot be undone.

All devlogs, followers, and associated data will be removed.

Followers

Loading…