Building a Motorola 68000 Emulator in the Browser ๐ฅ๏ธ
Building a Motorola 68000 Emulator in the Browser ๐ฅ๏ธ
If you've ever taken a computer architecture course, chances are you've been forced to use Easy68Kโa Windows-only, decades-old tool for writing and running Motorola 68000 assembly. It works, but it hasn't aged well ๐ด.
I decided to build something better: an m68k assembly interpreter that runs entirely in the browser. No installation, no Windows dependency, no excuses. This is the story of how a small side project turned into a week-long sprint to implement every instruction I could get my hands on.
This project started as the foundation of my bachelor thesis in 2021, and with the help of Claude and GitHub Copilot, I've been able to modernize, rewrite, and complete it into something genuinely useful.
๐ง Day One: Modernizing the Foundation (March 12)
The project already existed in a basic form, but the codebase was showing its age. The first thing I did was rip out the old setup and modernize everything:
- โMigrated the entire project to TypeScript ๐
- โSwitched the build system to Vite 5 โก for lightning-fast dev builds
- โSet up a proper CI/CD pipeline with GitHub Actions
- โIntegrated Vercel Analytics to understand how people use the tool
- โUpdated the homepage and deployed it live
It felt like renovating a house before moving in. You don't see the plumbing, but everything runs smoother because of it.
๐ก๏ธ Day Two: Fixing the Cracks (March 13)
With the new foundation in place, it was time to address all the little things that had piled up. This was the "boring but necessary" day ๐ :
- โFixed a ReDoS vulnerability in
minimatchflagged by Dependabot - โReplaced the vendored
ace-buildseditor with the proper npm package - โSet up CodeQL analysis with correct workflow permissions
- โAdded block scoping in switch statements to squash subtle bugs
- โIntroduced a configurable execution delay so users can watch their code run step-by-step in real time โฑ๏ธ
- โThrew in a โญ GitHub star button in the navbar (every project needs one, right?)
Not glamorous work, but the kind of stuff that separates a toy project from something people can actually rely on.
๐ Day Three: CI/CD Wrangling (March 16)
Ah, CI/CDโthe thing you set up once and then fix forever ๐.
package-lock.json kept falling out of sync, tests were flaky, and Codecov wasn't reporting correctly. I spent this day:
- โSimplifying the CI workflow into something maintainable
- โFixing package-lock sync issues (the bane of every Node.js project)
- โGetting Codecov integration working properly
Two PRs merged, pipeline green โ . Moving on.
๐งฎ Day Four: The Instruction Sprint Begins (March 17)
This is where things got fun. I started actually implementing the M68K instructions I'd been putting off:
- โMULU and DIVU โ unsigned multiply and divide ๐ข
- โBranch instructions (
BRA,BEQ,BNE,BCC,BPL,BGE,BGT,BLE,BLT,BVC) - โSTOP โ halt execution
I also focused on developer experience:
- โWrote an ultimate_test.asm file to stress-test every feature
- โMade error messages way more descriptive โ instead of "Unknown operation," you now get context about what went wrong and where
- โCleaned out old JavaScript files that were left over from the pre-TypeScript era ๐งน
๐ Day Five: Going All-In (March 18)
March 18th was the big one. I sat down and said "I'm implementing everything" ๐ช.
Data movement:
- โ
MOVEQ,MOVEM,MOVEP,PEA
Extended arithmetic:
- โ
ADDX,SUBX,NEGX,CMPM
Shift & rotate:
- โ
ROXL,ROXR
Bit manipulation:
- โ
BTST,BCLR,BCHG
CCR operations:
- โ
ANDI to CCR,ORI to CCR,EORI to CCR,MOVE to CCR,MOVE from CCR
More branching:
- โ
BSR,BSET,BLS,BHI,BCS,BMI,BVS
System control:
- โ
NOP,RESET,RTE,TRAP,TRAPV,CHK,LINK,UNLK,TAS
That's 30+ instructions in a single day. Each one with proper flag handling, size variants (.B, .W, .L), and edge cases. My coffee consumption was... significant โโโ.
๐ Day Six: Bug Hunting and Polish (March 19)
With all those instructions in place, it was time to make sure nothing was broken. Turns out, a few things were ๐ฌ:
- โLabels starting with
AorDwere being incorrectly parsed as register names โAGAIN:was treated as address registerA. Fixed the parser to properly distinguish labels from registers. - โEnd-of-arguments errors weren't being caught cleanly โ tightened up the argument parsing logic.
- โRan the full test suite, fixed everything that turned red ๐ดโ๐ข
Finally, I updated the README and the Help page with the complete list of supported instructions. Two final PRs merged, and the project was in a state I could be proud of.
๐ By the Numbers
Looking at the week in total:
- โ60+ commits in 8 days
- โ50+ M68K instructions fully implemented
- โ9 pull requests merged
- โ0 installations required to use it
The emulator went from a basic proof-of-concept to a genuinely useful tool that covers nearly the entire M68K instruction set that students encounter in courses.
๐ฑ What's Next
There's always more to do. The roadmap includes:
- โData Definition instructions โ
DC(Define Constant),DS(Define Storage),DCB(Define Constant Block) - โI/O Operations โ file and console input/output support
- โExamples folder โ comprehensive assembly examples with step-by-step annotations
But for now? It works. It runs in your browser. And it's free and open source.
โจ Final thought: What started as "Easy68K is annoying" turned into one of the most rewarding coding sprints I've ever had. Sometimes the best motivation is scratching your own itch. โจ