Virtual processor Simpleton 4

Discussion of development of software for any "obsolete" computer or video game system.
Post Reply
User avatar
aa-dav
Posts: 153
Joined: Tue Apr 14, 2020 9:45 pm
Location: Russia

Virtual processor Simpleton 4

Post by aa-dav » Mon Feb 01, 2021 3:18 am

https://github.com/aa-dav/Simpleton4

As title says it's fourth generation of 'simpleton famility'. From the beginning it was inspired by 'Gigatron TTL', but now it is something very different.

First of all: memory and registers are 16-bit wide.
There are eight registers R0-R7 and 128Kb of 65636 16-bit memory cells.

So, instruction opcode is 16-bit wide too. There is the only one instruction format:
Image
Every instruction takes two operands X and Y, writes them into ALU with operation code (INSTR) and writes result to the destination R.
So, fields X, Y and R are registers codes 0-7. Plus bit of indirection (XI, YI, RI) which tells to work with memory cell register points to.
So, every instruction has format: R = Y op X, where op is operation code. Square brackets around operand mean indirect mode. I prefer such syntax in assembler too.

Registers R5-R7 have synonyms and special features:
R5 - SP - stack pointer - post-increments after indirect reading and pre-decrements before indirect writing.
R6 - PC - program counter - always post-increments after indirect reading
R7 = PSW = processor status word (flags, including enable/disable interrupts). Indirect reading/writing is meaningless, so it works as 'immediate indirect' address mode (data from *PC++ serves as address of memory cell we work with).
Immediate data is available as indirect PC reading because after reading instruction code PC post-increments (as always) and points to next word and will be advanced to the next word after indirect reading.

So, we could have next instructions in asm syntax:

Code: Select all

R0 = R1 + R2 ; regular add
R1 = R1 +c R3 ; add with carry
[ R2 ] = 100 + R4 ; add R4 with immediate (PC+indirect) 100 and write it to memory R2 points to
[ R3 ] = R4 + [ 200h ]  ; immediate indirect [ 200h ] (PSW+indirect)
[ 100 ] = 20 + [ 101 ] ; register-free 4-word-long instruction
There are 16 ALU operations possible.
Some of them treats field XI+X of instruction as 'inplace immediate -8..+7'.

Current INSTR codes:
00 - ADDIS - add Y with INPLACE immediate in XI+X silent (doesn't update flags!)
01 - ADDI - add Y with INPLACE immediate in XI+X
02 - ADDS - add silent (doesn't update flags)
03 - ADD - add
04 - ADC - add with carry
05 - SUB - sub -
06 - SBC - sub with carry
07 - AND - and
08 - OR - or
09 - XOR - xor
10 - CMP - compare (as if Y - X)
11 - CADD - conditional add. never updates flags. (see below!)
12 - RRCI - rotate Y right (cyclic) by INPLACE immediate bit, carry gets last rotated bit
13 - RRC - rotate Y right (cyclic) by X bit, carry gets last rotated bit

Notes:

- If operation doesn't update flags we use <- instead of = in asm.

- There is no separate MOVE opcode because it's ADDIS with 0 in XI+X:
R0 <- R1 + 1
R1 <- [ R2 ] + 0
[ R2 ] <- R1
[ R3 ] <- [ 100 ]

- wrriting immediate in PC is JUMP and adding (silent) PC with immediate is relative JUMP:
PC <- address ; JUMP
PC <- PC + offset ; RELATIVE JUMP

- conditional add is the key to the conditional branching, it works in this way:
X argument (16 bit) is decoupled in two parts: upper 3 bits are conditional code and lower 13 bits are sign-extended to 16 bit of -4096..+4095 addendum. But if condition is false - ALU skips addition and returns Y without changes.
So, to implement conditional branching we just do:
PC <- PC +condition OFFSET
Assembler provides automatic offset calculation for labels of course.
For simplicity alternate syntax is supported:
JNZ LABEL

- CALL may be implemented as:
[ SP ] <- PC + 2 ; It's short ADDIS 1-word instruction
PC <- ADDRESS ; ADDRESS is immediate, so this instruction is 2-word. That is why we PUSH in stack PC+2

- RET is just:
PC <- [ SP ] ; Again, it's ADDIS opcode

- ADDI could be used as move with updating flags (testing move, useful in loops like STRCPY).

Code: Select all

StrCpy: ; R1 - pointer to src, R2 - pointer to dst
  [ R2 ] = [ R1 ] ; it's ADDI instruction
  JZ Exit
  R1 <- R1 + 1
  R2 <- R2 + 1
  PC <- StrCpy
Exit:
  PC <- [ SP ] ; ADDIS as RET
- Disabling/enabling interrupts is just simple as:
PSW = PSW & mask1
PSW = PSW | mask2 ; ~mask1 of course

I have emulator + assembler for Simpleton 3 and I'm in process of remaking it for subj. So there is nothing to show right now.
Last edited by aa-dav on Sat Feb 13, 2021 11:22 pm, edited 4 times in total.

User avatar
aa-dav
Posts: 153
Joined: Tue Apr 14, 2020 9:45 pm
Location: Russia

Re: Virtual processor Simpleton 4

Post by aa-dav » Mon Feb 01, 2021 10:58 pm

Having previous version of Simpleton 3 it was easy to make quick progress in implementing Simpleton 4.
Most assembler commands have syntax:

Code: Select all

CMD R Y X
where R is destination and Y and X are operands.
If X is omitted it becomes immediate 0.

Very simple assembler implementation works. I defined input-output port which behaves like console input/output in host environment (Linux/Windows) like now.
So this program:

Code: Select all

PORT_CONSOLE    = $FFFF

		move sp $70	; Setup stack

		move r0 str0	; shortcut for addis r0 str0 0
		call str_print	; shortcut for addis [ sp ] pc 2 : addis pc str_print 0
		move r0 str0
		call str_print
		dw 0 ; STOP

str_print	movet r1 [ r0 ]
		jz .exit		; shortcut for cadd pc pc _calculated_constant_ (mix of offset and condition code)
		move [ PORT_CONSOLE ] r1	; output char to console
		addi r0 r0 1	; increment r0
		move pc str_print	; jump to the beginning of procedure
.exit		ret			; shortcut for move pc [ sp ]


str0		dw "Hello, world!" 10 0
So, it outputs 'Hello, world!" string twice as planned.

User avatar
aa-dav
Posts: 153
Joined: Tue Apr 14, 2020 9:45 pm
Location: Russia

Re: Virtual processor Simpleton 4

Post by aa-dav » Thu Feb 04, 2021 9:31 am

I am not experienced in schematics and hardware creation, but I hope some day I will have enough time to learn more about it and create Simpleton-based system in real hardware (FPGA).

Another thing which seems like challenge is interrupt handling.
The problem is: interrupt ignition (like in typical CPU) is a too complex thing for Simpleton base design: R = Y op X.
Simpleton cannot do CALL in single instruction, but interrupt is more complex task!

But I think it could be solved without breaking Simpleton rules.
Main instrument of solution is indirect PC reading: [ PC++ ] is used in so many places:
- reading instruction opcode
- reading immediate data (like $100)
- reading immediate indirect (like [ $100 ] (which is [ PSW ] in opcode, but it is implemented as [ PC++ ] giving address of memory cell we work with)
So... Let it be in this way: external signal of interrupt request engages special mode of [ PC++ ] indirect PC reading: it stops to read from main memory and post-increment PC. This is just bit in flags (PSW register) and if it is set - [ PC++ ] addressing mode starts to read from little internal CPU buffer of 8 or 16 words. This buffer contains program with immediate data (but it's invisible for any other reads).
It can contans program like this:

Code: Select all

addis [ sp ] pc 2 ; prepare return address, remember that direct PC reads/writes work as usual
move pc irq_handler ; point pc to irq_handler
or [ sp ] psw disable_special_mode_mask ; save flags without 'special mode' flag to stack (see below)
or psw psw disable_special_mode_mask ; This is there special [ PC++ ] mode will be shut off and program will continue from new PC
(7 words long)
That is - this internal 'special mode handler' executes CALL instruction (delayed until we exit special mode) which pushed return address to stack, points PC to interrupt handler, saves flags to stack and then disables 'special mode'. After that program continues in normal mode, but in irq handler.
So, return from interrupt will be usual code in ROM/RAM:

Code: Select all

move flags [ sp ] ; restore flags
move pc [ sp ] ; return to program interrupted (RET pseudoop is available)
I think we could do many many things with such internal 'microcode' despite Simpleton has very simple instruction format.
Note, that jumps are not possible in this internal buffer because no special program counter is visible to CPU. But it exists and is set to 0 then special mode flag is set.

So, I think interrupts activation could be implemented not so hard in Simpleton 4 without complex logic of unusual instruction code/format.

User avatar
aa-dav
Posts: 153
Joined: Tue Apr 14, 2020 9:45 pm
Location: Russia

Re: Virtual processor Simpleton 4

Post by aa-dav » Sat Feb 06, 2021 9:09 pm

One thing I always dislike in assemblers is symbolic syntax which is verbose and unintuitive.
So, I implemented math-notation for Simpleton 3 which uses C-like expressions like in 'R0 += [ label ]'.
Simpleton4 instruction set makes it harder to implement math-notation, so I started from classic assembler as above.
But math-notation will be implemented in Simpleton 4 too.
Most of instructions could be expressed as 'R = Y op X' where 'op' is operation sign.
If X is omitted it becomes literal '0' (zero).
If 'op' is omitted it becomes '+' sign, so pseudoinstruction 'move' is not needed anymore (see below).
Next instructions fulfill this pattern (example for R=R0, Y=R1 and X=[ label ]):

Code: Select all

02 - ADDS  - r0 = r1 +s [ label ] ; add silent (doesn't update flags)
03 - ADD  - r0 = r1 +  [ label ] ; add
04 - ADC  - r0 = r1 +c [ lavel ] ; add with carry
05 - SUB  - r0 = r1 -  [ label ] ; sub
06 - SBC  - r0 = r1 -c [ label ] ; sub with carry
07 - AND  - r0 = r1 &  [ label ] ; and
08 - OR   - r0 = r1 |  [ label ] ; or
09 - XOR  - r0 = r1 ^  [ label ] ; xor
0A - CMP  - r0 = r1 ?  [ label ] ; compare (as Y - X), op updates flags and returns Y
0B - CADD - r0 = r1 +? [ label ] ; conditional add. never updates flags.
0D - RRC  - r0 = r1 >> [ label ] ; rotate Y right (cyclic) by X bits
But there are 3 opcodes (right now) which fall out of this pattern and have special syntax:

Code: Select all

00 - ADDIS - r0 <- r1 - 1         ; add Y with INPLACE immediate in XI+X SILENT (flags are not updated)
01 - ADDI  - r0 <= r1 + 3         ; add Y with INPLACE immediate in XI+X
0C - RRCI  - r0 <= r1 >> 15       ; rotate Y right (cyclic) by INPLACE immediate bits
First of all - it's 'inplace immediate' commands: addi, addis and rcci. These of them who updates flags use '<=' as sign of this special case.
The only exceptions is 'addis' which uses '<-' to signal that it's not updates flags.

Note, that 'addis a b -1' (negative inplace immediate) could be expressed in new syntax as 'a <- b + -1'. But also 'a <- b - 1' is correct (that is like 'sub' opcode). This is another reason for exclusion of addi(s) from regular '=' syntax.
Also, 'move' is as simple as: 'a <- b' which is shortcut for 'a <- b + 0'.

Note, that all pseudoops used for simplicity are still in place: 'jnz/call/ret' and so on.

So, example above could be rewritten as:

Code: Select all

PORT_CONSOLE    = $FFFF

            sp <- $70       ; Setup stack

            r0 <- str0      ; shortcut for addis r0 str0 0
            call str_print
            r0 <- str0
            call str_print
            dw 0 ; STOP

str_print   r1 <= [ r0 ]           ; testing move (addi r1 [ r0 ] 0)
            jz .exit           
            [ PORT_CONSOLE ] <- r1 ; output char to console
            r0 <- r0 + 1           ; increment r0
            pc <- str_print        ; jump to the beginning of procedure
.exit       ret                    ; shortcut for move pc [ sp ]

str0        dw "Hello, world!" 10 0
However this is to be implemented.
Last edited by aa-dav on Fri Feb 12, 2021 9:36 pm, edited 3 times in total.

lidnariq
Posts: 10241
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: Virtual processor Simpleton 4

Post by lidnariq » Sat Feb 06, 2021 9:39 pm

Before long you'll be looking through the APL unicode points and thinking you want to use those for your assembly mnemonics :mrgreen:

User avatar
aa-dav
Posts: 153
Joined: Tue Apr 14, 2020 9:45 pm
Location: Russia

Re: Virtual processor Simpleton 4

Post by aa-dav » Sat Feb 06, 2021 11:06 pm

lidnariq wrote:
Sat Feb 06, 2021 9:39 pm
Before long you'll be looking through the APL unicode points and thinking you want to use those for your assembly mnemonics :mrgreen:
:) Nah, I'm totally ok with this. ASCII is mandatory.

User avatar
aa-dav
Posts: 153
Joined: Tue Apr 14, 2020 9:45 pm
Location: Russia

Re: Virtual processor Simpleton 4

Post by aa-dav » Sat Feb 13, 2021 1:31 am

New (math-)assembler syntax is implemented and pushed to github.
Keyword 'mode' switches between modes: 'mode classic' and 'mode new'.
So, code just above should be started with 'mode new' line.

Post Reply