Hacker News new | past | comments | ask | show | jobs | submit login
OUP/M: CP/M-like operating system for 6502 (github.com/option8)
83 points by ingve on Nov 3, 2018 | hide | past | favorite | 21 comments



For another CP/M take on 6502 see DOS/65 at http://www.z80.eu/dos65.html


6502 is a harsher environment than Z80 which CP/M was originally designed for. It's a good candidate for a C64 port too.


Having moved to the 6502 from Z80 back in the day, I initially had that feeling too -

what? Only 3 8-bit registers on the 6502? The Z-80 had an abundance which is not trivial to describe (7 8-bit ones, 6 of which group into 3 16-bit pairs, an exchangeable shadow register file for them, and two additional 16-bit index registers); Z-80 also had block move instructions and other nice stuff that was missing from the bare bones 6502.

And yet, the 6502 eventually comes out at least as useful with the indirect addressing and page-0 -- to the point that it often feels like you have 128 16-bit registers, or 256 8-bit registers, or any combination of those.

Z80 is more high-level, but it comes at a cycle/instruction cost, and 6502 indirect indexing goes a very long way.


what makes it harsher? Also I believe CP/M was originally designed for the i8080.


I guess it's about the 6502's more RISC-like philosophy, which made it a bit more cumbersome to program in assembly code (even though the resulting performance was mostly similar to the Z80 because the 6502 could do more things in fewer cycles).

Even with the whole 'extended register set in the zero page', the 6502 didn't have convenient features like 16-bit math, memory block instructions, and even 8-bit math was less convenient (e.g. no separate add/adc, sub/sbc instructions, so you always had to clear the carry flag before a math operation etc...)

But I think this didn't matter for porting the operating system CP/M itself to 6502, the actual problem was binary compatibility with applications, and the Z80 was backward compatible with the i8080 (as long as only documented instructions were used).

I guess being compatible with the i8080 (and CP/M 'office software') was the whole point why the Z80 was even created (as an i8080 killer), and that it was as successful as it was.


CP/M predates the Z80 CPU by a few years. It was designed for the 8080.


There was a version for the 128K +3A though.


The Z80 was designed to be i8080 compatible (for the documented/recommended opcodes), so that it could run unmodified CP/M software.

The Z80 instruction set basically added new opcodes where the i8080 instruction set had gaps or redundant opcodes (e.g. the i8080 had 16 identical NOP instructions, and 4 identical CALL instructions, but only the lowest opcode was recommended to be used, if one of the redundant opcodes was used, the program ran on an i8080 but not on a Z80).


Is there a C compiler for it?


Probably not a very good one. 6502 architecture is quite hostile to c compilers


That's true, but the 8080 (and Z80) on which CP/M ran were not much friendlier to compilers, even if they were friendlier to humans.


Z80 is quite OK with its real stack and the 16 bit registers. Almost exactly the same as the "small" (64 k data, 64 k instruction, IIRC) memory model in Borland C for DOS, which I used quite a lot back in the day. Only occasionally did my programs get large enough that I had to increase the memory model.


The 8086 you used with Borland C is far from orthogonal (orthgonaliry, together with a large register file is what makes a cpu compiler friendly) - but it is significantly more orthogonal than the Z80.

And even the 8086 wasn’t compiler friendly - in those days I would easily outdo the compiler by a few hundred percents in right loops. I no longer dabble in assembly, but from what I heard, ARMs and AMD64 have gone far enough (as did compilers) that people rarely beat compilers on them.

People still win on vectorized architectures (GPU, AVX) and I suspect that will stop only when the languages become more vector friendly.


I'm not saying the Z80 is a wonder for compiler construction. But it's decent enough for a C compiler. It has a stack spanning the full address range (up to 64k), so all auto variables can be easily allocated on the stack. Arguments are typically also pushed on the stack in C. So the number of registers is not as important to a naive C compiler as is a decent stack. Oh, and the last, you on the Z80 also have easy absolute and relative addressing to all addresses, so you can easily implement global and static variables.

It feels very much like coding for a modern machine, just instead of having a memory limit of 2 gigabytes of RAM or whatever (for a 32 bit CPU) you have a limit of 64 kilobytes. And the integers are 16 bit instead of 32 bit, but again, this was normal in DOS too.

So that is why I made the comparison, C in CP/M or whatever on the Z80 didn't feel that much different from Turbo C on DOS.


Interesting - I grew up with a 6502-based computer (Atari 800), and never got around to using C. Any sources for this?

Edit: here’s one. https://dwheeler.com/6502/


A couple of major reasons:

1. The 6502 is heavily register-starved. Three limited-purpose registers is pretty rough.

2. There are no 16-bit registers, so you can't put a pointer in a register. You can put one on the zero page, but that's much more limited. Indexing into arrays larger than 256 bytes gets complicated, too.

3. The 6502's stack isn't well suited for storing data. There's no SP-relative addressing, for instance. It's possible to get the value of SP with PHP/PLA, but this is pretty awkward to work with.


I wrote a self-hosting (if you're very patient) compiler for the 6502 and Z80 a while back. Both are a bit of a shock if you're used to true 16 bit arch architectures. I did a couple of writeups on the problems of doing basic arithmetic in them:

http://cowlark.com/2018-02-27-6502-arithmetic/index.html

http://cowlark.com/2018-03-18-z80-arithmetic/index.html

The 6502 is more orthogonal, and while each instruction does less they're very fast; the Z80 is fundamentally more powerful but weirdly inconsistent, terrifyingly slow, and the unorthogonal register system means that you spend half your time shuffling registers.


Re: pointers, the same problem applies to int, which was always at least 16 bits. The 6809 and 8080/Z80 had 16 bit register (or register pairs) so must have been much better targets for C (among 8 bit machines).


It has a 256 byte stack, no multiplication/division, and if you look at typical 6502 code, a lot of it tends to be self-modifying - e.g. modifying the location of the most-significant-byte of addresses to copy more than 256 byes for example. That's a reasonable-ish thing to do when you have tens of KB of RAM available and can easily keep track of everything that's going on. But it's not very C friendly. It's certainly possible, and there are multiple C compilers as well as compilers for other languages, but most of the machines it's used on are small enough that using assembler and some macros tends to be closer to the sweet spot.


There are a number of c compilers for 6502. They all produce bad code and/or stray quite far from c. Looking at the architecture sort of explains why. Things c needs, it makes hard to do (pointer math, reasonably sized stacks)


cc65, a very good C compiler and assembler for the 6502 https://github.com/cc65/cc65




Consider applying for YC's W25 batch! Applications are open till Nov 12.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: