YCPU: an imaginary 16-bit processor.
Moderator: Moderators
YCPU: an imaginary 16-bit processor.
As a thought experiment, I've been dreaming up a 16-bit CPU. My goal is to create a relatively powerful processor with a comprehensive instruction set, but is limited to working on 16-bits of data at a time. The specification, which is hosted at Github, is released to the public domain under the CC0 waiver, and anyone may use it for any purpose without permission or attribution. Direct link to the YCPU Specification.
I've also implemented an emulator for this processor in C#, which is released under the MIT license. The emulator is also hosted at Github.
In this thread, I've been asking questions as the specification has matured. Thanks to everyone who has offered comments and suggestions and answered my questions: this community is exceptionally helpful.
I've also implemented an emulator for this processor in C#, which is released under the MIT license. The emulator is also hosted at Github.
In this thread, I've been asking questions as the specification has matured. Thanks to everyone who has offered comments and suggestions and answered my questions: this community is exceptionally helpful.
Last edited by pops on Sun Mar 23, 2014 9:44 pm, edited 22 times in total.
Re: Addressing modes for a fake cpu - what would you include
Recommend you look at the WDC 65816, which is a 16-bit CPU fully backwards-compatible with the 6502, to get an idea of what addressing modes are useful.
Re: Addressing modes for a fake cpu - what would you include
If R is register and I is immediate:
This might be a usable set of addressing modes (assume the stack pointer is one of the eight general purpose registers, possibly so is the program counter (in which case an immediate value addressing mode isn't needed)).
Code: Select all
I
R
[R]
[R+I]
[R+[I]]
[[R]+I]
[--R]
[R++]
[url=gopher://zzo38computer.org/].[/url]
Re: Addressing modes for a fake cpu - what would you include
You don't need to implement any addressing modes at all on most instructions. ALU operations such as addition can be register := register op register or register := register op constant. You only need addressing modes for the load and store instructions.
And even then, the only modes you really need are register+register and register+constant. Instead of having a more complicated address generator on the CPU, you can have the program running on the CPU calculate addresses with standard ALU instructions, which might let you run the rest of the CPU faster.
As for how offsets are interpreted: Is this 16-bit address space 65536 bytes (32768 words) or 65536 words? If 65536 bytes, what do you do with a 16-bit load from an odd address?
And even then, the only modes you really need are register+register and register+constant. Instead of having a more complicated address generator on the CPU, you can have the program running on the CPU calculate addresses with standard ALU instructions, which might let you run the rest of the CPU faster.
As for how offsets are interpreted: Is this 16-bit address space 65536 bytes (32768 words) or 65536 words? If 65536 bytes, what do you do with a 16-bit load from an odd address?
Re: Addressing modes for a fake cpu - what would you include
Look at MIPS maybe: http://en.wikipedia.org/wiki/MIPS_architecture
It does things quite a bit differently then you may be used to if you only have knowledge of 6502 and may give you some ideas.
It does things quite a bit differently then you may be used to if you only have knowledge of 6502 and may give you some ideas.
Re: Addressing modes for a fake cpu - what would you include
Having used both ARM and X86, ARM lets you do crazy stuff in address modes [r1 + r2 << r3], while X86 lets you use arbitrary memory with almost any instruction.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
Re: Addressing modes for a fake cpu - what would you include
Speaking of MIPS, I designed a 16-bit MIPS-inspired CPU called KIPS with 14 instructions while I was in college. (The thing was supposed to have 15, but I never got shift working.)
ALU ops: MOV, ADD, SUB, SLT (compare), AND, OR, XOR, two operands, second either a register or a 9-bit signed immediate value. These had two encodings: high nibble 8-F if the reg was
Other ops: LUI (load 16-bit immediate value shifted left 8; for use with OR to load a 16-bit value), LDR (load register with word at 6-bit offset from address in another register), STR (store), BNE/BEQ (add to PC if register is nonzero or zero), JSR (move PC to a register and add a 9-bit signed offset to PC), and RTS (move a register to PC). No flags; SLT puts the result in a register, and 32-bit quantities are added the same way 64-bit quantities are added on MIPS.
I seem to remember the instruction encoding looking something like this:
ALU ops: MOV, ADD, SUB, SLT (compare), AND, OR, XOR, two operands, second either a register or a 9-bit signed immediate value. These had two encodings: high nibble 8-F if the reg was
Other ops: LUI (load 16-bit immediate value shifted left 8; for use with OR to load a 16-bit value), LDR (load register with word at 6-bit offset from address in another register), STR (store), BNE/BEQ (add to PC if register is nonzero or zero), JSR (move PC to a register and add a 9-bit signed offset to PC), and RTS (move a register to PC). No flags; SLT puts the result in a register, and 32-bit quantities are added the same way 64-bit quantities are added on MIPS.
I seem to remember the instruction encoding looking something like this:
Code: Select all
FEDCBA9876543210 ALU opcodes, second operand constant
||||||||||||||||
|||||||||||||+++- ALU function code inspired by 74*381 ALU:
||||||||||||| 0=shift, 1=compare, 2=subtract, 3=add,
||||||||||||| 4=xor, 5=or, 6=and, 7=mov (use second operand
||||||||||+++---- Destination register
|||||||+++------- Second operand
||||+++---------- First operand
++++------------- 0
FEDCBA9876543210 ALU opcodes
||||||||||||||||
|||||||+++++++++- Second operand, 9-bit signed
||||+++---------- First operand and destination
|+++------------- ALU function code
+---------------- 1
FEDCBA9876543210 LDR/STR
||||||||||||||||
||||||||||++++++- Offset from address
|||||||+++------- Register containing address
||||+++---------- Data register
++++------------- Memory opcode
FEDCBA9876543210 Conditional branches (whether or not a reg is nonzero)
||||||||||||||||
|||||||+++++++++- Signed value to add to PC if check succeeds
||||+++---------- Register to check
++++------------- Branch opcode
Re: Addressing modes for a fake cpu - what would you include
I'm thinking of a cpu with multiple general purpose registers, not an accumulator and two index registers. I realized while reading this document that despite months programming the 6502, I still have no idea what indexed indirect [ (value, x) ] addressing could be useful for, compared to indirect indexed [ (value),y ].koitsu wrote:Recommend you look at the WDC 65816, which is a 16-bit CPU fully backwards-compatible with the 6502, to get an idea of what addressing modes are useful.
The inclusion of [R++] in place of Immediate addressing is clever. Sold. Where would I use --R?zzo38 wrote:If R is register and I is immediate:Code: Select all
... [--R] [R++]
I hadn't thought of this problem... and after spending the afternoon musing about it, I still have no idea what the correct solution is. My initial thought is that a 16-bit load from an odd address shouldn't be a problem, just load the low byte from the odd address and the hi byte from the even address.tepples wrote:As for how offsets are interpreted: Is this 16-bit address space 65536 bytes (32768 words) or 65536 words? If 65536 bytes, what do you do with a 16-bit load from an odd address?
Would the better solution be to ignore the bit0-address line when loading 16-bit? What about the PC? Loading [PC++] should evaluate to PC += 2, I guess. But that's completely counter-intuitive. How do other CPUs handle this?
Re: Addressing modes for a fake cpu - what would you include
It's generally pretty useless.pops wrote:I still have no idea what indexed indirect [ (value, x) ] addressing could be useful for, compared to indirect indexed [ (value),y ].
Re: Addressing modes for a fake cpu - what would you include
Indexing into an array of pointers. e.g. C's argv[n][0].pops wrote:I still have no idea what indexed indirect [ (value, x) ] addressing could be useful for
PIC assembly includes a set of special registers (and instructions) that provide preinc, postinc, predec, and no change.The inclusion of [R++] in place of Immediate addressing is clever. Sold. Where would I use --R?
In any case, postinc and predec are obvious pairs for a software stack.
IMO, you should forsake bytes altogether and natively address 65536 words.Would the better solution be to ignore the bit0-address line when loading 16-bit? What about the PC? Loading [PC++] should evaluate to PC += 2, I guess. But that's completely counter-intuitive. How do other CPUs handle this?
Re: Addressing modes for a fake cpu - what would you include
But it only works in zero page .. zero page is normally too precious to waste on setting up arrays of pointers. Relevant discussion: http://forum.6502.org/viewtopic.php?f=2&t=2538lidnariq wrote: Indexing into an array of pointers. e.g. C's argv[n][0].
Re: Addressing modes for a fake cpu - what would you include
I think the only place I've used (d,x) on the NES is in my music engine, where I store a bunch of data pointers per channel on zero page, indexed by channel X (where X=0, 4, 8, 12). In fact, apart from cases like this where you have multiple streams of data accessed in parallel, it's so otherwise unused that the Missile Command PCB repurposes it as a "screen access" instruction, with a circuit to recognize the (d,x) opcodes and temporarily remap the VRAM for individual pixel access.
Re: Addressing modes for a fake cpu - what would you include
Same here. Looks like this addressing mode is very specific to music ^^I think the only place I've used (d,x) on the NES is in my music engine, where I store a bunch of data pointers per channel on zero page, indexed by channel X (where X=0, 4, 8, 12).
I think it happened to me once to need plain indirect without indexing on 6502, and that I've used ($xx,X) instead of ($xx),Y because scrapping X was better than scrapping Y in that particular situation.
Re: Addressing modes for a fake cpu - what would you include
That's an interesting idea - but that would completely preclude byte access. I suppose you could still emulate byte load and store with masking and shifting. But you would need an extra bit of address to select the hi or lo byte of a 16-bit word. What about chars and strings?lidnariq wrote:IMO, you should forsake bytes altogether and natively address 65536 words.Would the better solution be to ignore the bit0-address line when loading 16-bit? What about the PC? Loading [PC++] should evaluate to PC += 2, I guess. But that's completely counter-intuitive. How do other CPUs handle this?
Here's an alternative, although I don't necessarily think it's better: data access is byte-aligned, instruction access is word-aligned. There's 0x10000 bytes of data and 0x8000 words of instructions which share the same space.
Re: Addressing modes for a fake cpu - what would you include
Separate instruction and data memory GO!
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!