
Show HN: I made an easy-to-understand 6502 emulator in pure C - haldean
https://github.com/haldean/x6502
======
jsaxton86
One of the most interesting parts of this code to me was the switch statement
in the main loop. Professionally, I have run into programs that have massive
switch statements with hundreds of cases in them, which I've always considered
a "code smell". Your approach is interesting -- breaking everything up into
logical groups, putting them in separate files, then using the preprocessor to
put everything back together -- that's the first time I've seen that.

I'm still not sure how I feel about it -- you could argue that you have the
same problem, but now it's spread out over many files. At the same time, I can
look at the loop and have a pretty good idea of what it does and I can easily
find what I'm looking for. I guess without OO, there isn't a great solution to
the problem, although yours is probably a slight improvement, with the added
bonus of getting me to think about the preprocessor in a new way.

Good work.

~~~
EpicEng
Even with OO, what would you suggest? A bunch of classes, classes,
inheritance, and virtual methods to replace it? Great, now my logic is spread
out all over the place.

I know that there are definitely cases in which an OO approach beats a bunch
of switch statements scattered throughout the code (specifically, when
checking the type of the input variable), but I don't think that applies here.
If I saw an interpreter written in that way I would assume it was created by
someone who didn't know what they were doing.

As an aside, 1) I can't stand the term "code smell" as it tends to be used by
hipsters with little to no experience building complex systems, and 2) I
realize that you posted your honest thoughts and did a good job of analyzing
the approach taken by the author. I'm not trying to prop up a straw man here.

~~~
fit2rule
I just wanted to say that 'code smell' predates hipsters as a term, yo, and a
lot of very experience engineers are right when they say 'this code smells'
(i.e. I am suspicious of its suitability for consumption..) In my experience
the term is something I learned in the 70's from the smelly retiring hippies
whose code I had to maintain for a decade or so. ;)

~~~
dalke
"code smell" in the use that EpicEng complained about dates from the late
1990s.

To get a sense of its history,
[https://books.google.com/ngrams/graph?content=code+smell&yea...](https://books.google.com/ngrams/graph?content=code+smell&year_start=1997&year_end=2008&corpus=15&smoothing=3&share=&direct_url=t1%3B%2Ccode%20smell%3B%2Cc0)
put a start date of around 1998. It was definitely in Fowler (1999)
"Refactoring: Improving the Design of Existing Code".

See also [http://c2.com/cgi/wiki?CodeSmell](http://c2.com/cgi/wiki?CodeSmell)
, which claims "A code smell is a hint that something has gone wrong somewhere
in your code. ... KentBeck ... seems to have coined the phrase in the
"OnceAndOnlyOnce" page" and points to "Refactoring" as earliest known use.

The phrase you refer to - "this code smells" \- and the implication that it
reflects hygiene, has different meaning and intent. While related, they are
not the same thing as a "code "smell." Compare "the wine smells" vs. "wine
smell" to get a sense of how there can be a difference.

The modern use of the term "hipster" dates from 1999-2003, claims Wikipedia at
[http://en.wikipedia.org/wiki/Hipster_%28contemporary_subcult...](http://en.wikipedia.org/wiki/Hipster_%28contemporary_subculture%29)
, but it's easy to find things like the 1998 alt-comic "Urban Hipster #1" at
[http://www.indyworld.com/uh/uh01.html](http://www.indyworld.com/uh/uh01.html)
which predate 1999 and use hipster in its modern meaning.

In any case, the term 'hipster' is derived from a term in widespread use from
the 40s-60s, which then fell into disfavor. To get a rough idea of the change
in use pattern, see
[https://books.google.com/ngrams/graph?content=hipster&year_s...](https://books.google.com/ngrams/graph?content=hipster&year_start=1800&year_end=2008&corpus=15&smoothing=3&share=&direct_url=t1%3B%2Chipster%3B%2Cc0)
.

Obviously the 1940s "hipster" term predates "code smell" as applied to
computer code, because there was no computer code in the 1940s.

So no, "code smell" does not predate the term "hipster."

~~~
diggitydoggity
fit2rule didn't say that the term 'code smell' outdates the term 'hipster'. He
said that the term 'code smell' outdates hipsters' use of it. Heck, even I
remember hearing about a code smell or two in the 80's ..

~~~
dalke
Ahh, I see how you can draw that conclusion. The quote is "'code smell'
predates hipsters as a term", which I interpreted to mean that "code smell"
(as a term) is older than "hipster" (as a term, or as a movement), while you
interpret to mean "was used by people before hipsters used it."

I agree with you that "code smell" did not originate from hipster use.

But I don't think EpicEng implied that either. The parent comment is "it tends
to be used by hipsters with little to no experience building complex systems."
I don't see in it an implication that hipsters came up with the term.

So if that is fit2rule's point, then it's rather like saying "fixed-wheel
bicycles existed before hipsters" \- true, but a tangential remark which ended
up derailing the conversation.

I know of no use of the phrase "code smell" before 1999, with its modern use.
Could you speak more about your recollections from the 1980s? Was it used the
same? Do you have a citation or reference?

~~~
EpicEng
Yeah, pretty much, and I admit it is a gross generalization. The term just
bugs me because I see it used so often by people who lack the experience to
understand why code which may not seem optimal to them was written the way
that it was. I've also seen it used by smart people who know what they're
talking about.

Who knew I would get such an education on the term "code smell"? :)

------
anatoly
Good job! As promised, the code is easy to read. Your major choices all make
sense to me:

* you went easy on #define's, they obfuscate the code when used heavily

* you have a simple switch instead of an opcode table with function pointers or something like that (may seem more fun to write, harder to read for someone inexperienced)

* light on comments, which is also excellent, the code is self-documenting almost everywhere.

* the unusual includes for opcode categories are OK. If you wanted it to be more straight-laced C, could put them in separate .c files and break the switch into many switches, one per file. It's probably better the way it is.

One thing it'd be nice to add is a short guide, right there in README, in
which order to read the source (e.g. start from cpu.h/cc to understand how the
state of the CPU and memory is represented, then cpu.h/cc for the main loop
executed once per instruction, etc.).

~~~
haldean
Thanks so much! That's a great idea; I'll write that up.

------
ggambetta
I made something similar for the Z80:
[https://github.com/ggambetta/libz80](https://github.com/ggambetta/libz80)

The interesting thing is that I wrote very little of the code by hand; instead
I wrote a program that generates the opcode implementations from a concise
specification. The end result is remarkably compact, and the whole thing was
really fun to make.

~~~
userbinator
A little hint for improvement: condition() could be implemented as a switch
instead of a long if-chain.

Did you use this for generating the opcodes? The Z80 ISA encoding is quite
regular and octal-based:
[http://www.z80.info/decoding.htm](http://www.z80.info/decoding.htm)

~~~
ggambetta
Thanks for the reference! This was a long time ago but I think I didn't use
that decoding table. Just a couple of days ago I was reading about the x86
one, I really wasn't aware that opcodes were anything but random bytes mapped
to operations.

As for the improvement, I never liked switch, for unknown reasons :) You mean
an improvement in style, performance or both?

~~~
userbinator
There's always a pattern to the opcodes, even though in some cases it's not
quite so obvious (like x86 - it's octal too). The reason has to do with how
it's implemented in hardware. The 6502's is only slightly less regular than
the z80 and here's an interesting article about that:
[http://www.pagetable.com/?p=39](http://www.pagetable.com/?p=39)

IMHO the switch would improve both style and performance, what caught my eye
when I looked over the code was that different flags would require different
amounts of time to execute, which _really_ seems an odd thing for an emulator
to do.

------
s-macke
Reminds of my little 6502 CPU project for the TI92 calculator.

[http://simulationcorner.net/index.php?page=c64](http://simulationcorner.net/index.php?page=c64)

Only 30KB of code and it runs a C64 on it.

------
Luc
6502 is still currently used, by the way. The Tamagotchi games use a
GeneralPlus 6502C, for example. There's a new Tamagotchi out this week that
has NFC but is so much like the previous version otherwise, it's probably
still using the same code:

[http://natashenka.ca/tamagotchi-friends-
teardown/](http://natashenka.ca/tamagotchi-friends-teardown/)

~~~
csmuk
The 6502 is still used widely in industrial stuff. Back in 2001 when I was
still doing electrical engineering bits, as part of a project I received some
brand new custom radio rig test equipment to integrate with an automated
testing rig plugged into a PC running DOS (meh). We took it to bits to get
access to the documented serial port header. Inside was a pristine gold turned
pin socketed 6502. It was the only chip on the board that had that privilege.
It was like it was being worshipped by the engineers.

We sent the test team who built it a big "you're awesome" card.

------
mambodog
If you want to try this out without building it yourself, I've put together a
quick Emscripten port, including the two demos:
[http://jamesfriend.com.au/x6502](http://jamesfriend.com.au/x6502)

------
euroclydon
So I'm working on an AVR emulator in pure C when I have time. 'tptacek gave me
some hints on getting started:
[https://news.ycombinator.com/item?id=5787373](https://news.ycombinator.com/item?id=5787373)

He suggested to take HEX as the input and I never looked back. I see this
emulator just reads the bytes from the binary.

Does anyone know if the GCC AVR toolchain spits out a file I could do the same
thing with?

~~~
haldean
Oh that's an interesting idea. I actually considered writing my own assembler
to some format that I could read, but then I realized:

* It's way cooler if you can use other peoples' assemblers and still have your bytecode interpreter work

* Using other peoples' assemblers is a good way to sanity check any assumptions you made (this bit me with branches, for example; I was branching from the location of the current instruction when the spec is to branch from the location of the next instruction)

* It's easier to read binary than to read hex strings and transform them to binary.

Plus, transforming binaries to readable hex is as easy as "hexdump -c". :)

------
slunk
"dispatching out to functions to handle each opcode carries unnecessary
overhead in what should be the tightest loop in the project"

How about inline functions or macros?

------
emilyst
Recommended way to assemble the 6502 examples on OSX?

~~~
voltagex_
Looking up bin/xa on Debian lead me to

    
    
        xa65 - cross-assembler and utility suite for 65xx/65816 processors
    

This package is available in the Mac homebrew repository, so maybe try that?

~~~
haldean
Ah yeah, sorry; xa65 is the package name on Debian as well.

