Robot Game: Comparing 6502 C, Assembly, and Forth
21–30 of 37 posts
Re: Robot Game: Comparing 6502 C, Assembly, and Forth
#22Nice project! Looks like it was fun to work on.
Re: Robot Game: Comparing 6502 C, Assembly, and Forth
#23Any multiplication where one multiplicand is a constant should be much faster with shifts and adds than with a loop. mult5, e.g. is: x+(x<<2)
Re: Robot Game: Comparing 6502 C, Assembly, and Forth
#24The 6502 is still doing hundreds of millions of units a year, and is still a terrific introductory processor that is comparatively easy to wrap your head around, especially if you are interested in board bring up from scratch. (Compare the requirements to boot a 68000 to a 6502 into a nop loop, for example.) The 6502 is far from dead.
Re: Robot Game: Comparing 6502 C, Assembly, and Forth
#25Re: Robot Game: Comparing 6502 C, Assembly, and Forth
#26Is the mult5 example an actual piece of code of your program? Any multiplication where one multiplicand is a constant should be much faster with shifts and adds than with a loop. mult5, e.g. is: x+(x<<2)
Re: Robot Game: Comparing 6502 C, Assembly, and Forth
#27I wonder if the author is familiar with the PLASMA [1] language and bytecode VM for 6502-based Apple computers. That might be another interesting option to add to the comparison. [1]: https://github.com/dschmenk/PLASMA
Re: Robot Game: Comparing 6502 C, Assembly, and Forth
#28> This brings us to one of the main shortcomings of Forth. If you need to access more than three local variables at once (in the body of a loop for example) there is just no convenient way to do so. [...] Consider the variables used in this C function that draws 1 bit-per-pixel images with optional rounded corners: > int DrawTile1bpp Looking at the C version, the argument "tile" is used once in the function, to get t…
> Looking at the C version, the argument "tile" is used once in the function, to get the pointer to the tile. The pointer could be passed directly: one less local.
The argument "tile" is an 8-bit index, which is faster to pass than the 16-bit pointer to the tile. More importantly, that index is used for things other than looking up the tile pointer, such as finding color pairs to recolor the tile. In other words, you could pass the 16-bit tile pointer directly, but you'd still need a way to correlate that pointer with its matching color data, and that system would be slower than using the same 8-bit index for both.
> x and y are passed only to calculate an address, this address could be passed directly
That would be more efficient and save a handful of cycles when the function is called. This does not answer the original criticism, however. As I mentioned on the page, x and y go away after the pointer is calculated, so I'm not counting those as variables that need to be available in the loop body. You still have over a dozen variables that you can't manage efficiently in Forth.
> t0 seems to be always 0, except when it is undefined.
Good point!
> The t_height, t_with are just offsets in the tile structure. This locals can go away too
I don't think I see your point. If you're going for performance, doing one array access and saving the value saves a lot of cycles compared to indexing into the array each iteration, which eats a lot of cycles.
> trans_row only exists to set skip_pixel, it seems one of them can go away. The logic seems to be "unless trans_row and something, do something". The C version might actually be more verbose than necessary.
You could get rid of one of them at the expense of readability. Or maybe there is a good name that would indicate both purposes.
> Finally, the edge_style complicates a lot the logic. Using one function to do different things because it is so simple to "just add another parameter" is typical in many HLL, and often result in awful spaghetti code.
I don't think this function is awful spaghetti code. Yes, the logic is complicated. I mention on the page that I encoded the data for some tiles as 1 bit per pixel to save room and decided to make rounded transparent corners in code depending on a flag stored for each tile. This function is a compromise to save memory. Otherwise, you could just encode the tile like any other and have three colors including transparency but take up 8 times more memory.
> Actually even in C some follow certain naming conventions - like #defines being all caps, member things being prefixed by m_, etc. And you can do that in Forth too. Once again, "write only" has more to do with the author than wit the language.
I really disagree on this one! All caps and so on for constants is nice but still does not tell you how many values, if any, a word pops and how many it leaves behind. That alone earns the "write only" label. For example: CONST_A m_foo CONST_B m_bar. What does m_foo return and what arguments does m_bar take?
Thanks for the comments!
Re: Robot Game: Comparing 6502 C, Assembly, and Forth
#29The 6502 is still doing hundreds of millions of units a year, and is still a terrific introductory processor that is comparatively easy to wrap your head around, especially if you are interested in board bring up from scratch. (Compare the requirements to boot a 68000 to a 6502 into a nop loop, for example.) The 6502 is far from dead.
Glad to hear it! I first learned assembly for 6502 on the Apple ][, and found it indeed easy to wrap my head around. Great machine, great architecture, TED II Editor/assembler was amazing...
Re: Robot Game: Comparing 6502 C, Assembly, and Forth
#30This nicely provides empircal evidence on the slowdown of using Forth, which seems to be around 10 to 20 times slower than optimized assembly. I was initially surprised by how poorly Forth performed on all counts of speed, memory usage and development time. For something as complex as a game the lack of a type system and postfix nature make Forth quite unsuitable. When I use Forth, it's often for high-level applicati…
If you program Forth like it's C, and then use a non-optimizing compiler, you're going to have a bad time (e.g. 10/20x slowdowns). I've written Forth compilers that generated output that was ~25% slower than optimized assembly, without putting that much work into it. There are companies that will sell you a much better compiler [0], at prices even approachable to hobbyists. [0] - https://www.mpeforth.com/software/pc-…
This particular distribution also ships with GTK+.
That being said, a simple "3 2 1 ?" (I was unsure what word would dump the stack) SIGSEGVs quite consistently.
It's also 32-bit, and the backtrace handler produces "XXXX:XXXX" style addresses (?).