6 ms·
Show HN: Z80 Compiler Visualization
- rcarmo 9y agoThis is amazing. It's particularly neat to watch how it handles things like "x * 16 + 500000" by splitting integers and using bit rotation.
- mtkd 9y agoat the time Z80 was popular ('87 ish) there were few/no tools outside of Hisoft Devpac (http://www.secarica.ro/images/zx/genp351.gif http://www.secarica.ro/images/zx/genp351.gif) neither was there any internet / forums etc. to learn how others were solving things - like that bit rotation example when I found out people were moving the stack pointer register to the screen memory base address and using stack pushes (instead of mov) to move data - to save a clock cycle or two each byte move - it blew my mind - hacks like that would be common knowledge in minutes now
- vardump 9y ago> when I found out people were moving the stack pointer register to the screen memory base address and using stack pushes (instead of mov) to move data - to save a clock cycle or two each byte move ... So the user might occasionally see interrupt stack frame on screen?
- mtkd 9y agomemory is hazy, but using SP to move the memory was fast enough you could blit most (not all) of a screen in one refresh cycle - which is, I think, why games like Uridium (https://www.youtube.com/watch?v=TvULd4zHz8Y https://www.youtube.com/watch?v=TvULd4zHz8Y) were running the main gameplay in a smaller area also, on that Uridium vid - notice how they are using the standard font but spacing it out vertically (so they could save memory)
- vardump 9y agoAlso no level destruction scene. Intra-level minigame was also completely missing. Leaving those out must have saved some memory too.
- timthorn 9y agoThere were lots of magazines and books though - eg the works of R.A.Penfold.
- jacobparker 9y agoI really like stuff like this. This tool is amazing for C++: https://godbolt.org/ https://godbolt.org/ It's really handy for popular architectures and it's nice that it has "real" compilers (GCC vs. clang vs. ICC.) I find it fun to compare small pieces of code between the different compilers. ---- Shameless plug for an abandoned project of mine: (note: these demos appear to work in the latest Chrome on a wide monitor - YMMV; I didn't know what I was doing.) Back in 2012 I wanted to learn JS and had some ideas about a UI for teaching C programming with good visualizations. I was interested in building tools that would allow you to visualize in-memory data structures and step through the code (so you could watch a sorting algorithm, or tree manipulation, that kinda stuff.) Anyway the full thing never panned out but I've got some lower-level demos: Here's a UI for running MIPS-like assembly: http://csclub.uwaterloo.ca/~j3parker/things/evalc/evalc3/mips/ http://csclub.uwaterloo.ca/~j3parker/things/evalc/evalc3/mip... (Hit "run" and click "faster" a few times) It started off as straight-MIPS but I realized emulating a real machine wasn't necessary for the overall goal (teaching C and the C abstract machine) so I started adding convenient op-codes. All words (I think) of memory had tags to specify if the memory was initialized (maintained by the VM) stack/heap (maintained theoretically by the C runtime) or code/data. The goal was to make a C machine that was maximally friendly for education. Here's a C REPL that compiles to that assembly and runs it on the VM: http://csclub.uwaterloo.ca/~j3parker/things/evalc/evalc/ http://csclub.uwaterloo.ca/~j3parker/things/evalc/evalc/ it compiles on keyup (I had vague goals of very quick feedback) and there is a line-edit below the source code that you can put C expressions into (e.g. type "fib(12)" without the quotes and hit enter - it should print 233 if you haven't modified the code.) The parser is mostly-complete C99 (typedefs were an issue - the first parser used a YACC-like generator which is known to have troubles here - the next version used a hand-rolled recursive descent parser. That one didn't get finished but also had way better error messages, as expected.) The compiler (semantic analysis + codegen) didn't support much of the language though, e.g. it doesn't know how to code-gen for > but it knows <. So, the compiler is not at a very usable state. I also had a V2 of the VM with an insane fixed 8-bit instruction set (with 200+ instructions) for a stack-based (not register) machine with a 32 bit address space. It would generate (with a poorly written bash script) the VM from the LaTeX documentation for the CPU which was weird. Here's the PDF: http://csclub.uwaterloo.ca/~j3parker/things/evalc/evalc2/vm/docs/cpu.pdf http://csclub.uwaterloo.ca/~j3parker/things/evalc/evalc2/vm/... the .tex file (in the same directory) has the impl of the instructions (not rendered to the PDF - that was the intent though) and it generates this: http://csclub.uwaterloo.ca/~j3parker/things/evalc/evalc2/vm/vm.js http://csclub.uwaterloo.ca/~j3parker/things/evalc/evalc2/vm/... It never did get finished but it had some promise. --- It was a fun short project that got abandoned. I still think there would be value in an educational implementation of C, something that conforms to the spec but is in no way performant--instead, UB sanitizers everywhere and special hooks inside the runtime to aid in visualization and debugging (e.g. I want to look at memory and see all the allocations with links back to what line of code allocated this word of memory, etc.) Source code (it's all really bad): - VM: https://github.com/j3parker/mipsjs/blob/master/mips.js https://github.com/j3parker/mipsjs/blob/master/mips.js - Jison grammar/parser: https://github.com/j3parker/jcc/blob/master/c.jison https://github.com/j3parker/jcc/blob/master/c.jison - Better, but incomplete recursive-descent parser: http://csclub.uwaterloo.ca/~j3parker/things/evalc/evalc2/parser.js http://csclub.uwaterloo.ca/~j3parker/things/evalc/evalc2/par... - Compiler: https://github.com/j3parker/jcc/blob/master/jcc.js https://github.com/j3parker/jcc/blob/master/jcc.js
- trevyn 9y agoNice, but I wouldn't call it a visualization. More like a "live preview" or "instant compiler" or something. Also, why is it so laggy? It feels like it's being sent to a server for compilation, but it looks like it's all in JavaScript. (And V8 is honking fast, should be nearly instant.)
- sehugg 9y agoIt's all done in a worker running asm.js modules. I've found it to be fastest on Firefox. Would love to speed it up; haven't found the magic emscripten flags yet.
- sehugg 9y agoActually, I'd like to try WebAssembly, but I keep getting "TypeError: Module.asm.__GLOBAL__I_000101 is undefined" errors when trying to run it.
- deleted 9y ago[deleted]
- dorfsmay 9y agouh! Adding a number to itself for multiplication by 2 instead of one quick shift to the left?
- sehugg 9y agoThe Z80 has no 16-bit shift instruction, but has 16-bit add/subtract :)
- vardump 9y agoOther than the obvious 8 vs 16 bit issue: I don't know any platform where bit shift left is faster than addition. Usually it's just as fast. But on some platforms, you need to first clear carry bit, because they only have rotate and rotate through carry instructions available.
- ravishah 9y agoI used to love the zilog z80, so super happy to see this Used to use it for automation and running FORTH...
- geori 9y agoAhh. I remember doing lots of TI82/83 calculator programming in Z80 and never considering using a C to Z80 compiler since it was so suboptimal. C was considered slow and a memory hog. Most of these (other than the sprite routine) aren't that bad. Every byte counted when you only had 26KB free.
- richard_shelton 9y agoIt would be nice to have a superoptimizer for Z80 in a form of web tool. You provide a C expression to it and the tool will return in turn the shortest code sequence. Demosceners would love it. Superoptimization: https://en.wikipedia.org/wiki/Superoptimization https://en.wikipedia.org/wiki/Superoptimization I found this long abandoned project which is described in non-English, see the examples on the bottom of the page: http://www.ricbit.com/mundobizarro/superopt.php http://www.ricbit.com/mundobizarro/superopt.php
- vardump 9y agoUs firmware developers would also love it! Something like that could easily save real money. 8-bit C-compilers are pretty bad. For example Keil C51 compiler produces binaries about 2x too large and 2-4x too slow, even with maximum level optimizations.
- vardump 9y agoCode generation is probably missing somewhat trivial optimizations. Here's one example: int func(int x) { return x * 1; } ...still produces unnecessary stack manipulation: 0000 C1 [10] 56 pop bc 0001 E1 [10] 57 pop hl 0002 E5 [11] 58 push hl 0003 C5 [11] 59 push bc 0004 C9 [10] 60 ret Plain "ret" would have been enough.
- Lerc 9y agoDepends on how it expects the parameter and the result. If the parameter is the second item down on the stack and the compiler wants the result in hl with the stack unchanged. pop bc pop hl push hl push bc isn't redundant stack manipulation. it's moving stack values to bc and hl while keeping the stack unchanged. Of course at another level a compiler should be able to inline x=>x*1 but that depends on the build architecture. If it's a linkable function then the contents may be opaque to the code that calls it.
- vardump 9y agoOk, seems like you're right. In SDCC function params are always passed on stack, but return value in HL. So pop hl/push hl moves function parameter to return value register HL. (pop/push bc is of course just used to get past return address value in stack.) Seems odd compiler doesn't pass parameters in registers in a relatively register rich z80 arch.
- Questron 9y agoThere's also something else: Try shifting unsigned char x to right. >> 1 through 3 produce correct results, 4 changes the shift to some optimization too early, and the >> 5 the correctly optimized version. It's definitely not a very good compiler.
- faragon 9y agoStill not being very efficient generating Z80 code, the SDCC is amazing! :-) P.S. SDCC mirror in GitHub: https://github.com/svn2github/sdcc https://github.com/svn2github/sdcc
- Xcelerate 9y agoThis brings back a lot of memories. I remember in high school printing out a sheet of Z80 opcodes (at size 6 font), writing a program on a sheet of paper, and then manually compiling that program and typing in the hex codes (using the AsmPrgm instruction to prefix the program). It was great for boring classes as long as you sat far enough in the back. As a prank, we started grabbing people's calculators and turning off the LCD display using some sequence of assembly. Restarting the calculator wouldn't fix it, so you either had to memorize the button sequences to re-enable the display or remove the batteries and let it sit for a while.
- chairmanwow 9y agoHow on earth did you work out how to program assembly through button presses on a calculator? Sounds like a stunning prank though.
- Xcelerate 9y agoThe TI graphing calculators have a mode for writing your own programs. Typically this is done using TI-BASIC, but if you prefix the program with the AsmPrgm symbol, it will allow you to directly write Z80 opcodes as hex values. Combined with a TI-provided guide for making bcalls (calls into common routines that have already been written, like changing LCD settings or multiplying floats), it's not too difficult to write a short ASM program by hand.
- mikeknoop 9y agoFun times. I did the same hand compiling back in middle school on a couple long plane flights where I didn't have access to a full compiler. Shame this never shipped: http://www.detachedsolutions.com/main/oldnews.php?item=58 http://www.detachedsolutions.com/main/oldnews.php?item=58
- stevekemp 9y agoI did the same thing with my ZX Spectrum - writing programs in assembly language on paper, then manually looking up each opcode in the table at the back of the manual. After writing out all the opcodes I'd then have to work out the values to use for any relative jumps, once I knew how long each instruction had been. Finally the whole thing would be POKEd into memory, and tested. Writing code like that, without a compiler/assembler was simultaneously a lot of fun and utterly exhausting. I know I got into the habit of putting in random "nops" just in case I had to add new functionality in later revisions - that would allow some unconditional jumps to be patched into place to avoid having to change offsets, etc.
- sytelus 9y agoGiven that Z80 is super easy to learn assembly language, this is a great introduction on how C code would internally. I would suggest give the option for 8085 too as the its so much similar.
- andrepd 9y agoZ80 isn't actually that easy. It's a quirky little chip, I'd much sooner recommend the 6502 for an assembly beginner.
- ucs 9y agoAs luck would have it, the very same site under discussion also happens to host a neat online "IDE" for learning all about the 6502-based Atari 2600¹. It is a companion to the book, "Making Games for the Atari 2600". A wonderfully clear and concise primer that I thoroughly enjoyed, even though I had no interest in the Atari 2600 per se. The NES was my first console -- and naturally the one I'd always wanted to program. Since it shares the same 6502 processor, I used this book as an introductory text before diving into the murkier waters of NES development wikis and forums. ¹ http://8bitworkshop.com http://8bitworkshop.com
- Digit-Al 9y agoAh. Good old Z80. For some reason, C9 has become indelibly burned into my brain.