8 ms·
Scamp CPU: A homebrew 16-bit CPU with a homebrew Unix-like-ish operating system
- rurban 5y agoA OS in perl, ha! Lights my heart
- dusted 5y agoVery impressive!
- juice_bus 5y agoAre there many resources available for someone who has an interest in putting together a basic OS on top of older hardware? Lets say 6502 for an example - where would someone who is experienced with much higher languages (C#/Java, etc) begin to even learn something like that?
- jacquesm 5y agoGet a nice book on assembly and try to implement something that is simple enough to totally overview (say, making a traffic sensitive traffic light controller or something like that) starting at the reset vector. You can make your life a lot simpler by using an emulator.
- Syonyk 5y agoLearn C and dive in. The various "osdev" communities are good places to hang out, though I personally find IRC to be somewhat better than the forums and such. If you can reason about the code you write in a memory-byte-accurate and handwavingly "what it actually uses in assembly" manner, you can start in. Most hobby OS projects don't ever get past toy stage, a few do. Unix, however, was designed to be portable, so getting Unix-like OSes running on all sorts of random stuff is easier than writing from scratch.
- wk_end 5y agoC on the 6502 is pretty painful.
- homarp 5y agosee https://news.ycombinator.com/item?id=27324653 https://news.ycombinator.com/item?id=27324653 A project to port LLVM to the MOS 6502 and http://calc6502.com/RobotGame/summary.html http://calc6502.com/RobotGame/summary.html comparing ASM, C and Forth of the same program
- duskwuff 5y agoExtremely painful. * There are only three data registers (A, X, Y), and they aren't interchangeable. Values get spilled to the stack or memory constantly. * Memory addresses are 16 bits, so they cannot be stored in registers at all, and performing even simple operations on them (like incrementing an address) requires carry handling. * The stack is hard-limited to 256 bytes, so pushing too many temporary values onto the stack risks stack overflow. * Addressing modes are limited. There is no "address + immediate offset" addressing mode, making pointers to dynamically allocated structures awkward to work with, and some indexed addressing modes will roll over if they're used to index past the end of a 256-byte page.
- NobodyNada 5y ago* There's also no stack-relative addressing mode (unless you move the stack pointer to the X register). * No instructions to push or pop anything besides A or status flags. The combination of all of this basically means there's no good way to do local variables on the 6502. IIRC the C compilers typically reserve a bunch of memory for a separate "C stack" to avoid these limitations, but this is rather inefficient in terms of both performance and memory use. Idiomatic 6502 assembly tends to have a mindset of "all variables are global", with only a few bytes for temporary/intermediate values that you have to juggle around carefully and deliberately.
- pjmlp 5y agoUNIX wasn't designed to be portable, it became portable around V5 edition.
- wk_end 5y agoThe 6502 is a CPU, not a full machine - and the OS really is about interacting with the whole machine. You need to learn about a specific 6502-based system - the C64, the Apple II, the NES... Moreover, usually when you’re writing a 6502 program, you’re writing a program targeted towards an individual machine, with no OS in the way - the program you’re writing is written against a particular machine; it effectively is the OS. So the answer is: learn how to write programs for a 6502-based machine first. Then, make your program an OS. Your ability to make it anything like a modern OS is going to be limited, though.
- jstanley 5y ago(Hi, this CPU is my project). I got into this stuff by buying an RC2014[0] kit and putting it together, and learning a bit about how CP/M works on it. If you're interested in that sort of thing, you could do much worse than buying an RC2014 and just writing low-level programs for it for fun. CP/M is really incredibly simple. You have some "kernel" type stuff towards the top of memory, with routines for reading/writing files on disk, and interacting with the console and a paper tape "reader + punch". When you type a command, the named program is loaded from disk into memory starting at 0x100 and then execution starts at 0x100. To interact with hardware, the program calls the kernel's routines (analogous to system calls). And that's basically all there is to it. The OS for my CPU is very similar in operation to CP/M, but more pleasant to use for someone coming from a Unix background. [0] https://rc2014.co.uk/ https://rc2014.co.uk/
- martijnvds 5y agoWait a minute, is that why DOS .com files are loaded at 0x100? CP/M compatibility?
- jstanley 5y agoNot sure! I doubt they would actually be compatible anyway since the CPU is too different. It seems likely that prior experience with CP/M COM files being loaded at 0x100 influenced the design though.
- monocasa 5y agoYeah, QDOS was a CP/M clone for 8086. It wasn't source compatible, but was 'major ideas and structure compatible'.
- wvenable 5y agoYes. The Program Segment Prefix is designed for CP/M compatibility: https://faydoc.tripod.com/structures/13/1378.htm https://faydoc.tripod.com/structures/13/1378.htm
- 5y ago
- wvenable 5y agoDo I have the website for you: https://eater.net/6502 https://eater.net/6502 I've build the computer and simple OS/Monitor.
- codedokode 5y ago6502 is a very simple CPU and you can learn all of its instructions in several hours. But as it uses 1-address instructions, the code gets pretty verbose. For example, to add 10 to a variable you will have to write: LDA var CLC ADC #10 STA var That's 4 lines and many keypresses for a single addition! You might want to invent slightly more high-level language that would compile into assembly, like this: var, var2 = variables(2) var += 10 var2 << 5 # Assign 5 to var2 By the way, you can use Python and operator overloading so that the lines above written in Python will generate assembly code when executed. I have used << instead of = in assignment because Python doesn't allow to overload it.
- whartung 5y agoThe early OS's were pretty simple. The best way to learn about these things is to study the other early ones. Some were little more than a bunch of routines shoved in ROM with a BASIC on top. Others were a little more sophisticated. All of them were hacked and abused in unspeakable ways. They really only had to do a few things: boot from the disk, map files somehow to the disk, read/write/append to said files on the disk, and load and execute a program. Look for how each of the different systems tried to accomplish those tasks. CP/M is the classic to look at. But consider things such as the Apple ROM, and the Apple DOS. The C64 ROM and how rather than having a DOS per se, it relied on a very "smart" disk drive. Atari has CIO, "Central I/O", which is an extensible device system. There's also FLEX, which is akin to CP/M in that it was a portable OS for 6800 based machines. TRS-DOS for the TRS-80 is a fascinating study, it has some really interesting features you find nowhere else. Don't forget to look at the old Forth implementations, "language, editor, assembler and OS in 8K of memory". It's very (very) simple, but many folks in the day used it. It needs little more than block disk I/O. But, at the time, thats easier said than done if you take in to account things like sector interleave and other exotic disk layouts. The computers were so slow that you didn't put sectors back to back on the floppy disk. This is because while trying to read two consecutive sectors, by the time the system got done handling the read of the first sector, the second sector (assuming it was adjacent) would have passed the head already and you'd have to wait until it all came around again, which slowed things down dramatically. So, you'd alternate sectors (1 every 2 or 3 sectors), "interleaving" the sectors along the track. Obviously not something you'd need to worry about with modern solid state storage, but back in the day mapping a simple "load sector 123" in to the appropriate track and sector on the disk drive was an entire little subsystem of the OS. The DOS part is the hardest part. Organizing files on the disk, keep track of the used sectors, the whole kit. There's a lot to do. The rest are little more than monitor routines. Read a serial port, write a serial port, handle an interrupt. All of the old OS's pretty much have source code published somewhere today that you can audit. They're all in assembly (Z80, 8080, 6502, 6800). But they're a good study. Doing a survey of them, you see how they try to all solve the same problems, but how they approach them in different ways.
- bullen 5y agoCheckout this awesome mock for a C64 OS: http://move.rupy.se/file/C64-NaxOS.jpg http://move.rupy.se/file/C64-NaxOS.jpg
- homarp 5y agoor the real thing: https://www.c64-wiki.com/wiki/GEOS https://www.c64-wiki.com/wiki/GEOS and http://toastytech.com/guis/c64g.html http://toastytech.com/guis/c64g.html (previous discussion of GEOS: https://news.ycombinator.com/item?id=10188367 https://news.ycombinator.com/item?id=10188367 )
- glhaynes 5y agoNice work, congrats! I think the most surprising thing to me is the lack of interrupts. If you read this, jstanley: did you struggle much with that decision? I think of interrupts as nearly universally available on 8-bit micros, much less 16, but I have also wondered before how important they really were for what those machines ended up being used for. The (S)NES polled their controllers' shift registers in a really inefficient way, but it turned out fine. On the other hand, though, the vertical blank interrupt was pretty critical to their software and, of course, it became extremely common for NES cartridges to add extra chips to raise interrupts on particular horizontal scanlines. But, aside from neat graphical tricks, maybe interrupts just weren't all that important?
- tenebrisalietum 5y agoThe Atari 2600 doesn't use IRQs or NMIs. You have to sync with the frame by setting a timer, making sure your code doesn't run over it, and spinlocking on it until it expires. However, the CPU can tell the video chip to make the CPU halt until the beginning of the next scanline though. That's the only platform I know of that's anything like interruptless.
- rzzzt 5y agoThere is a neat story told by Bil Herd about the C128's VDC video chip: https://youtu.be/wzMsgnnDIRE?t=597 https://youtu.be/wzMsgnnDIRE?t=597 > It turns out it didn't have an interrupt when you're done. And when I > figured out, well, the 6845 has got an interrupt, why don't you? I asked > the designer, he said "Well, you can simply look at a register" [...] From > then on, we had this running joke where nobody would wait for the phone to > ring, we just all kept checking our phones whenever this guy was around [...]
- retrac 5y ago> nearly universally available on 8-bit micros, much less 16, but I have also wondered before how important they really were for what those machines ended up being used for Usually available, yes. But not all that widely used by those systems. The stock Apple II for example, has nothing in it that can even generate an interrupt. You'd have to install an expansion card. The standard serial cards can generate an interrupt upon character receipt for example, but they were usually programmed with polled IO anyway. Later with network cards and hard disks, you do see some use of interrupts. > On the other hand, though, the vertical blank interrupt was pretty critical to their software The Atari 2600 had no hardware interrupt support at all. You could tell the graphics IC to sleep the CPU until the next scanline. You'd turn vblank on, generate 3 lines of vblank, then turn vblank off. You'd be lined up with vblank from that point if you counted carefully. On an in-order-execution processor, most things can in principle be translated into periodic polling and cycle counting. But it involves some extraordinarily painful coding. A timer and an interrupt are quite a relief when you're doing something time-sensitive.
- jp0d 5y agoNamed after this Scottish car? :) https://en.wikipedia.org/wiki/Scottish_Aviation_Scamp https://en.wikipedia.org/wiki/Scottish_Aviation_Scamp
- pkaye 5y agoIBM also has a computer called the SCAMP. https://en.wikipedia.org/wiki/IBM_5100 https://en.wikipedia.org/wiki/IBM_5100
- codedokode 5y agoI wanted to note that abbreviations for signals like DI or AI are not very good for understanding, long names like DATA_IN or ADR_OUT would be better in my opinion.
- mayapugai 5y agoCongratulations on getting this amazing machine working IRL. I think the best takeaway for me was the resources section of your README. It's veritable goldmine for anyone who wants to do something even remotely similar!
- int_19h 5y agoIs this in any way related to Udamonic Scamp (https://udamonic.com/what-is-a-scamp.html https://udamonic.com/what-is-a-scamp.html)?
- krallja 5y agoThey’re both 16-bit processors, but other than that appear unrelated. I like my Udamonic Scamp 3, but I was a little disappointed when I finally realized I could accomplish basically the same thing by putting FlashFORTH on a $3 Arduino Nano clone. The Udamonic board has an additional 16 LEDs built-in, which is nice.
- jstanley 5y agoNope, I only found out later that "SCAMP" appears to be the most widely used CPU name in history!
- spongeb00b 5y agoThe technical skills alone to do this are amazing, but what I'm absolutely in love with is the full on blinkenlights/rackmount/mini computer style of the hardware.
- hwestiii 5y agoThis is why I come to HN. To be shamed.