Virtual processor Simpleton 4

Discussion of development of software for any "obsolete" computer or video game system.
Post Reply
User avatar
aa-dav
Posts: 159
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

Github page: https://github.com/aa-dav/Simpleton4 (including most actual documentation)

Some of 8bit-guy videos including covering of project 'Gigatron TTL' inspired me to make some ISAs.
This is fourth generation of the same idea (see below).

First of all: this ISA is definitely suboptimal.
The only goal is to make instruction format as simple as possible keeping programming flexible and non-esoteric.
I know that code density could be improved, leading to something like MSP 430 as a result. So, it's not an option. :)

To simplify keeping up to date documentation I removed it from here and placed to github: https://github.com/aa-dav/Simpleton4
This theme will keep discussion and evolution of ISA through time.

Emulator + Assembler are provided.
Last edited by aa-dav on Thu Mar 25, 2021 10:28 pm, edited 5 times in total.

User avatar
aa-dav
Posts: 159
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: 159
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: 159
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
Last edited by aa-dav on Thu Mar 25, 2021 10:28 pm, edited 4 times in total.

lidnariq
Posts: 10463
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: 159
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: 159
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.

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

Re: Virtual processor Simpleton 4

Post by aa-dav » Tue Mar 02, 2021 9:06 pm

During discussion on another forum I was gifted with excellent idea!
(Many thanks to Lethargeek from https://hype.retroscene.org (russian resource)!)

In Simpleton 4 writing to indirect PC (like in 'move [ pc ] $100') is forbidden because of total meaninglessness (unlike indirect PC reading which implements 16-bit immediates).
But also 3-operand-style 'cmp' instruction acts strange ( like in 'r0 = r0 ? r1' - comparison returns first argument (Y) from ALU as result to be in touch with Simpleton architecture).

The idea is to ignore writing of result from ALU if destination (R) is [ pc ]!
ALU updates flags in operation, but result is ignored if destionation is [ pc ].
I bind keyword 'void' to indirect writing to PC in assembler and this allows to make non-destructing comparisons:

Code: Select all

sub void A B ; acts like 'cmp A B' in many other ISAs
jnz ...
or bit tests (of any kind):

Code: Select all

and void r0 $0001
jz ...
...or comparison of number with constant in range -8..+7 via one-word instruction (inplace immediate):

Code: Select all

addi void r0 -3
jz ... ; r0 is equal to 3
...or checking of i-th bit of operand via placing it in carry flag during RRCI instruction execution:

Code: Select all

rrci void r0 3 ; CF gets bit 3
jc ... ; jump if CF=1
This is truly amazing: by exploiting forbidden destination in this way we free up 'CMP' opcode and get a lot of more instructions and techniques in return! :D
Github page (code and documentation, link is in the very beginning of theme) already has these changes and it works!

Post Reply