YCPU: an imaginary 16-bit processor.

You can talk about almost anything that you want to on this board.

Moderator: Moderators

pops
Posts: 91
Joined: Sun Apr 04, 2010 4:28 pm

Re: YCPU: an imaginary 16-bit processor.

Post by pops »

psycopathicteen wrote:If you're going to have the MMU built in the chip, I still don't understand why you can't have the registers have their own selectable bank, since there's not going to be an absolute addressing mode. You can probably use two banks for program counter, to avoid the need of a long jump instruction.
If you mean having each general purpose register addressing a different 16-bit area of memory --- I'd rather keep the virtual address space 16-bits in its entirety.

Proposed boot sequence:

Code: Select all

============================[ 1.G. Boot Sequence ]==============================
At initial power on, the state of all memory, registers, and cache is unknown
with one exception: The Processor Status is set to $8000 (Supervisor mode, no 
features enabled).

At Power-On, the processor follows the following bootstrap sequence:
    LOD R1, %1010000000000000
    TRS R1, PS                      ; Enable Memory Paging, Supervisor Mode
    LOD R0, $0000                   
    TRS R0, IA                      ; IA table begins at $0000
    LOD R1, %1000000000000000
    MMW R0, R1                      ; MMU Bank 0 = ROM Bank 0
    .RESET                          ; Raise RESET Interrupt
(Note that I moved the supervisor bit from $4000 to $8000).
psycopathicteen
Posts: 3001
Joined: Wed May 19, 2010 6:12 pm

Re: YCPU: an imaginary 16-bit processor.

Post by psycopathicteen »

Each general purpose register r0-r7 will have it's own bank register b0-b7 for register indirect addressing.

For example:

mov b0,#$00ab
mov r0,#$cdef
move r1,(r0)

will address $abcdef.
pops
Posts: 91
Joined: Sun Apr 04, 2010 4:28 pm

Re: YCPU: an imaginary 16-bit processor.

Post by pops »

The addition of bank registers has been suggested at least once before, and is one of the few suggestions that I haven't included in the specification. I like to imagine the YCPU as a relatively powerful processor that is limited by its 16-bit registers and virtual address space.

In other words, it's like the Genie in Aladdin: Phenomenal cosmic powers! Itty bitty living space!

EDIT: Updated the spec on the first post to 0.2b, which includes the dedication to the public domain.
lidnariq
Posts: 10677
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: YCPU: an imaginary 16-bit processor.

Post by lidnariq »

Hm. Long addressing like that is sorta like the segment registers in x86 real mode. I'm not certain whether
1- having a full eight is useful
2- having those eight be uniquely mapped 1-to-1 for each register is preferable to dynamic pairing.
3- Poking a hole in the MMU is desirable. Given that the MMU has concepts of "supervisor" and "write prohibited" and "execute prohibited" ... probably not.
pops
Posts: 91
Joined: Sun Apr 04, 2010 4:28 pm

Re: YCPU: an imaginary 16-bit processor.

Post by pops »

lidnariq wrote:3- Poking a hole in the MMU is desirable. Given that the MMU has concepts of "supervisor" and "write prohibited" and "execute prohibited" ... probably not.
Would you mind clarifying this point lidnariq? I'm afraid I don't understand what you mean.
lidnariq
Posts: 10677
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: YCPU: an imaginary 16-bit processor.

Post by lidnariq »

Oh ... I guess if updating the "segment" register is a privileged operation it would still be secure. It does have some weirdness with having 64 KiW segment size for long pointers but only 4 KiW segment size for near pointers.
pops
Posts: 91
Joined: Sun Apr 04, 2010 4:28 pm

Re: YCPU: an imaginary 16-bit processor.

Post by pops »

tepples wrote:It's the kernel's job to configure the MMU for each process. I'd also recommend having a seventeenth page that replaces one of the pages in supervisor mode, so that the user process can see the full 64 Kwords.
I'm still considering this. More importantly, your comment made me realize that I had not considered that the state of the MMU was potentially unknown when an interrupt is raised - the bank of memory that contains the interrupt vector table might be switched out to some random page of data.

I realize there are at least two options here:
1. Always require that the bank of memory with the interrupt vector table be switched in at MMU bank 0 (occupying $0000-$0FFF).
2. Before handling an interrupt, the processor switches in a specific bank of memory, in which a process can store its interrupt vectors and the code that will call its handlers.

I've decided to go with the second route: when an interrupt is raised but before the interrupt vector is called, the processor switches in the first bank of memory to bank 0.

Code: Select all

=======================[ 3.F. Interrupt Instructions ]==========================

RTI         Return from Interrupt
Returns from an interrupt.
Processor is currently in Supervisor mode.
    1.  The word pair describing MMU bank 0 is          LOD R5,$0000
        popped from the Supervisor Stack, and           POP R6
        MMU bank 0 is restored to its original          MMW R5,R6
        bank using this data.                           INC R5
                                                        POP R6
                                                        MMW R5,R6
    2.  PS is popped from the Supervisor Stack.         POP R6
                                                        TRS R6,PS
    3.  PC is popped from the Supervisor Stack.         POP R6
                                                        TRS R6,PC
    4.  R5 and R6 are popped from the Supervisor        POP R5, R6
        Stack.
    5.  Q status bit is cleared.                        .CLEAR Q
    6.  Execution continues.                            
  
SWI         Call Software Interrupt
Raises the 'software interrupt' interrupt.
    1.  Q status bit is set.                            .SET Q
    2.  R5 and R6 are pushed to the Supervisor          PSH R5, R6
        Stack.
    3.  PC is pushed to the Supervisor Stack.           TSR R6,PC
                                                        PSH R6
    4.  PS is pushed to the Supervisor Stack.           TSR R6,PS
                                                        PSH R6
    5.  Supervisor status bit is set.                   .SET S
    6.  The word pair describing MMU bank 0             LOD R5,$0000
        is pushed to the Supervisor Stack.              MMR R5,R6
                                                        PSH R6
                                                        INC R5
                                                        MMR R5,R6
                                                        PSH R6
    7.  MMU bank 0 is switched to the internal          LOD R6,$0000
        processor memory bank 0.                        MMW R5,R6
                                                        DEC R5
                                                        MMW R5,R6
    8.  PC is set to Mem[SWI].                          LOD R5,[SWI]
                                                        TRS R5,PC
    9.  Execution continues.                    
pops
Posts: 91
Joined: Sun Apr 04, 2010 4:28 pm

Re: YCPU: an imaginary 16-bit processor.

Post by pops »

Latest version adds floating point instructions and an operation which allows load/store of an octet value from another register. I also implemented zzo38's suggestion regarding flag effects on shifts of zero bits

The specification has come a long way in the past ten days, and while I don't think this will be the last draft, I do think that it's not missing anything crucial. I'm ready to start working on the emulator, which I'll write in C#. I plan on releasing the emulator as open source under the same waiver.

Before I do so, if anyone has the time, I'd ask that they give the specification just one more once over, to see if I've missed any crucial instructions.
Last edited by pops on Wed Mar 19, 2014 11:16 am, edited 2 times in total.
Joe
Posts: 469
Joined: Mon Apr 01, 2013 11:17 pm

Re: YCPU: an imaginary 16-bit processor.

Post by Joe »

You describe reset as a series of instructions executed by the processor, but I've never seen anything like that before. Usually reset is just described as the initial values loaded into registers when the CPU executes, without explicitly describing how those values get there. For example:

Code: Select all

PS <- $A000
IA <- $0000
MMU[$00] <- $0000
MMU[$01] <- $8000
PC <- [$0000]
(By the way, your pseudocode doesn't seem to initialize the MMU correctly!)

In a similar vein, "RTI" and "SWI" are described as a series of instructions, but also use R5 and R6 as scratch variables. That contradicts your description of hardware interrupt handling, which makes no mention of those two registers.

And speaking of interrupts, why would the processor ignore SWI when interrupts are masked? How can the user interact with the supervisor when interrupts are masked? (Why does SWI set Q? Shouldn't hardware interrupts be able to interrupt most software interrupts? Why does RTI clear Q? It already restores PS, and explicitly clearing Q means you could get a hardware interrupt inside a hardware interrupt - that's bad!)

...Err, sorry if it sounds like I'm being harsh. :oops:
pops
Posts: 91
Joined: Sun Apr 04, 2010 4:28 pm

Re: YCPU: an imaginary 16-bit processor.

Post by pops »

Thanks Joe. I've really appreciate your comments, and I've updated the Bootstrap and Interrupt specifications to implement your suggestions. Specifically:
Joe wrote:You describe reset as a series of instructions executed by the processor, but I've never seen anything like that before. Usually reset is just described as the initial values loaded into registers when the CPU executes, without explicitly describing how those values get there.
It seems I've put how little I know about hardware on display again. The bootstrap sequence is now written as you suggested.
Joe wrote:In a similar vein, "RTI" and "SWI" are described as a series of instructions, but also use R5 and R6 as scratch variables. That contradicts your description of hardware interrupt handling, which makes no mention of those two registers.
Here, I think I was just being too enthusiastic with regards to imagining how the CPU might work. I've rewritten the RTI/SWI instructions to not include R5 and R6, included an explanation of how the processor responds to a hardware interrupt, and made sure not to clear the Q flag until the very last instruction.

Specification is updated to 0.2e, which I've posted on the first post of this thread. Changes as follows:

Code: Select all

0.2e 03/13/2014
	Complete rewrite of 'Interrupts' section.
	Added new 'P2' register which is used by the BankFault interrupt.
	Added new 'R' status bit in PS which defines if ROM or RAM should be
	switched to bank 0 on interrupt.
	Clarified what banks are loaded when the MMU is enabled/disabled.
	Clarified bootstrap sequence.
	Made MMR/MMW privileged instructions.
	Added Real Time Clock stub.
	Changed bit pattern of ALU to match FPU.
	Noted that Immediate addressing is not available with the STO opcode.
	Minor spelling errors.
The Specification is also available online as a text document.
Joe
Posts: 469
Joined: Mon Apr 01, 2013 11:17 pm

Re: YCPU: an imaginary 16-bit processor.

Post by Joe »

That makes a lot more sense now. (However, I did notice in §2.D.3, shouldn't it say interrupts restore PS, not FL?)

The only thing I have to ask right now is about this:
§2.D.2 wrote:software interrupts will not be acknowledged by the CPU if the I status bit is clear
What, exactly, happens when a program executes SWI when the I status bit is clear?
pops
Posts: 91
Joined: Sun Apr 04, 2010 4:28 pm

Re: YCPU: an imaginary 16-bit processor.

Post by pops »

After reading about which interrupts can be masked on other CPUs, I realize that SWI should be unmaskable. Thanks for pointing this out.
pops
Posts: 91
Joined: Sun Apr 04, 2010 4:28 pm

Re: YCPU: an imaginary 16-bit processor.

Post by pops »

I've started work on the emulator --- and am attempting to catch up on schoolwork from the past week. Neither of these tasks is continuing at a particularly fast pace.

I've been thinking about memory management again, from the perspective that this processor should be able to run an OS that can run multiple child processes. With this in mind, I'm trying to think of how a program written in C, that does not necessarily 'know' what underlying hardware its running on, and therefore has no direct control over memory banking, segment registers, etc., could access more than the 64kw virtual address space which I've specified.

The NES has 64kb of address space, but it can access additional banks of memory using a MMC. I have a similar scheme for my processor. It occurs to me that a single program on this processor would have no trouble with managing memory, as it would always know which banks it has access to and where all of its data is stored. This would certainly be true for a kernel...

... but child processes wouldn't know which banks they are located in, and therefore wouldn't know how to access additional memory. I have no background in OS theory - how could an operating system on this processor expose more memory to a child process?

On a similar note --- how does this work on a processor with segment registers? I see a similar problem: without changing the segment registers, a child process only has access to (# of segment registers * addressable units per segment register) address space. How does a child process on, say, a 286 know what segments are allowed for access? Does the kernel handle this?
lidnariq
Posts: 10677
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: YCPU: an imaginary 16-bit processor.

Post by lidnariq »

pops wrote:On a similar note --- how does this work on a processor with segment registers? I see a similar problem: without changing the segment registers, a child process only has access to (# of segment registers * addressable units per segment register) address space. How does a child process on, say, a 286 know what segments are allowed for access? Does the kernel handle this?
In practice, 286 protected mode was basically not used for anything (There were Xenix and Minix ports, but otherwise...), and with the advent of 386 protected mode's 32-bit pointers we mostly (but not entirely) ignored the segment registers.

C compilers targeting 8086 real mode (with segments) usually provided the concept of a "far pointer" which would use one of the segment pointers to deal with data bigger than 64 KiB. (here's DJGPP's comments) But they were really slow ... checking when you had to move bits between the segment and offset words added a costly amount of overhead.

Neither of these really help your question, which is how do you meaningfully provide the abstractions of "how do I address more than 64KiW of memory when my near pointers only allow 64 KiW". One thing that works to your advantage here is that you don't have the 8086's kinda-useful (for relocations) mostly-awful segmentation: there's no overlap (no segment<<4 + offset) and so the math is simpler. Regardless, you'll need help from both the kernel (to provide a series of 4 KiW slices that make a virtual larger chunk of memory) as well as from your compiler (to provide a notion of far pointers and handle requesting bank switches not on every memory access)
pops
Posts: 91
Joined: Sun Apr 04, 2010 4:28 pm

Re: YCPU: an imaginary 16-bit processor.

Post by pops »

Thanks lidnariq. I think I now have a much better handle on how memory paging will work. I'm still considering what the optimal page size might be: although I initially decided on 4 KiW, I'm aware that everything from context switching to loading large arrays of data would be sped up by larger pages (perhaps 8 KiW or 16 KiW). Programs that had large global sets of data or functions spread throughout memory and did not access these in ways that a compiler could predict and optimize would be slower, perhaps. Just different things to weigh.

I've completed a very basic console emulator that fills the memory space with random data and then executes the same. Not super impressive - and I have only a little more than half of the opcodes implemented and haven't even tested the output of those - but it's a start!
ycpu-emulator.png
Post Reply