View unanswered posts | View active topics It is currently Tue Apr 16, 2024 5:49 pm



Reply to topic  [ 24 posts ]  Go to page 1, 2  Next
 Virtual 16-bit CPU/ISA Simpleton (emulator + assembler) 
Author Message

Joined: Wed Feb 03, 2021 4:13 am
Posts: 19
Github page: https://github.com/aa-dav/SimpX (including most actual documentation https://github.com/aa-dav/SimpX#readme)
Online emulator and assembler: http://alxhost.tk/SimpX/SimpX.html

Some of 8bit-guy videos including covering of project 'Gigatron TTL' inspired me to make some ISAs and PC around it.
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. :)


Last edited by aa_dav on Sun Jun 20, 2021 3:46 pm, edited 11 times in total.



Wed Feb 03, 2021 4:48 am
Profile

Joined: Wed Jan 09, 2013 6:54 pm
Posts: 1780
Welcome! Simplicity and 16-bit word-addressable memory are two excellent choices!

I do hope you can share your sources: it seems you might have both an assembler and an emulator?


Wed Feb 03, 2021 10:06 am
Profile

Joined: Wed Feb 03, 2021 4:13 am
Posts: 19
BigEd wrote:
Welcome! Simplicity and 16-bit word-addressable memory are two excellent choices!

I do hope you can share your sources: it seems you might have both an assembler and an emulator?


Thank you.
Yes, I have sources for simple assembler and simple emulator.
I am newbe in git/github, so didn't publish them yet there.
But probably it's about time, so: https://github.com/aa-dav/Simpleton4
All code for asm/emul is in two Simpleton.cpp/h files.
A little bit of code in main.cpp shows how to apply assembler to file source.asm and execute result until NOP (addis r0 r0 0) instruction is met.
And a lot of bugs are still expected, so I whouldn't rely on this yet.


Last edited by aa_dav on Thu Feb 04, 2021 8:19 am, edited 1 time in total.



Wed Feb 03, 2021 11:40 am
Profile

Joined: Wed Jan 09, 2013 6:54 pm
Posts: 1780
Thanks for sharing! There's often a temptation to wait until a project is "finished" but that often leads to no result, so releasing early and often seems to be the best tactic.


Wed Feb 03, 2021 9:56 pm
Profile

Joined: Wed Feb 03, 2021 4:13 am
Posts: 19
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++ ] 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:
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
or psw psw disable_special_mode_mask ; This is there special [ PC++ ] mode will be shut off and program will continue from new PC

That is - this internal 'special mode handler' executes CALL instruction 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:
Code:
move flags [ sp ]
move pc [ sp ]

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.


Thu Feb 04, 2021 3:36 pm
Profile

Joined: Wed Feb 03, 2021 4:13 am
Posts: 19
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:
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:
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:
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 Fri Mar 26, 2021 5:26 am, edited 1 time in total.



Sun Feb 07, 2021 3:49 am
Profile

Joined: Wed Feb 03, 2021 4:13 am
Posts: 19
New (math-)assembler syntax is implemented and pushed to github.
Keyword 'mode' switches between modes: 'mode classic' and 'mode new'.


Sat Feb 13, 2021 8:30 am
Profile

Joined: Wed Feb 03, 2021 4:13 am
Posts: 19
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:
sub void A B ; acts like 'cmp A B' in many other ISAs
jnz ...

or bit tests (of any kind):
Code:
and void r0 $0001
jz ...

...or comparison of number with constant in range -8..+7 via one-word instruction (inplace immediate):
Code:
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:
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!


Wed Mar 03, 2021 4:04 am
Profile
User avatar

Joined: Fri Oct 20, 2017 7:54 pm
Posts: 8
The amount of special cases strips the "simple" from your ISA.

_________________
"Stay OmmmMMMmmmPtimistic!" — yeti
"Logic, my dear Zoe, merely enables one to be wrong with authority." — The 2nd Doctor
"Don't we all wait for SOMETHING-ELSE-1.0?" — yeti


Wed Mar 03, 2021 7:58 am
Profile

Joined: Wed Feb 03, 2021 4:13 am
Posts: 19
yeti wrote:
The amount of special cases strips the "simple" from your ISA.

I believe these special cases are nothing in comparison with titans of 8-bit epoch like MOS 6502 or i8080/Z80.
(It's almost impossible for me to memorize is some addressing mode of 6502 applicable to this/or/that instruction or not, for example)
Also, as was said in the beginning, goal is to be "as simple as possible, but not esoteric". Programming must be easy - without shifting bits by means of lookup tables like in Gigatron TTL.
So, I think Simpleton 4 is almost ideal combination of trade-offs and benefits. a = b + c single instruction format is cool for me. It's simple to program, not just simple instruction format! Simpleton 3 was more complex and constrained at the same time.

In fact full description of this ISA is two paragraphs of description of register set (with register's features), instruction format + opcode table. The rest of text is explanation of assembler syntax and consequences of register's features.
P.S.
Also, "Simpleton" as the name is something like fun juxtaposition to the serious "Gigatron brand". :)


Wed Mar 03, 2021 8:30 am
Profile

Joined: Wed Jan 09, 2013 6:54 pm
Posts: 1780
In the OPC journey, too, we found little spaces in the encoding which could readily be repurposed. And in that case, we stayed within our constraint of a single page of code - it's not an overly complex solution.


Wed Mar 03, 2021 10:04 am
Profile

Joined: Wed Feb 03, 2021 4:13 am
Posts: 19
I removed summary documentation from here to github to simplify specs and docs update.
Full set of flags and conditional codes are implemented now.
Possible conditional codes and their mnemonics:
Code:
z, nz, c, nc, s, ns, o, no - test of corresponding flag (n* for 'NOT set')
a  - unsigned 'above'
be - unsigned 'below or equal'
ge - signed 'greater or equal'
l  - signed 'less'
g  - signed 'greater'
le - signed 'less or equal'

For example: jg label
Conditional code in cadd (conditional move) instruction operand is expanded to 4 bits, so every aspect of Simpleton4 is fitted into quad-bit boundaries again. But conditional jumps are limited to +-2k offsets (in comparison with +-4k of earlier design).


Fri Mar 26, 2021 5:33 am
Profile

Joined: Wed Jan 09, 2013 6:54 pm
Posts: 1780
Thanks for the update! I know you have a link in the head post, and that's good, but here's another:
https://github.com/aa-dav/Simpleton4#readme


Fri Mar 26, 2021 10:30 am
Profile

Joined: Wed Feb 03, 2021 4:13 am
Posts: 19
BigEd wrote:
Thanks for the update! I know you have a link in the head post, and that's good, but here's another:
https://github.com/aa-dav/Simpleton4#readme

Thanks! I put this link in the head too.

I hope next week const-expr parser/evaluator will be ready and I will begin to connect emulator to SDL2 and emulation of some PC virtual hardware.
Interesting thing to think about video bit planes of 16 bit words...
SNES/SMD had 16-bit video bus, but true granilarity of video data was 8 bit.
Simpleton4-based system must have plain bit planes screen, but 16 bit granularity is something new for me... But definitely there will be no hi-color. :)


Fri Mar 26, 2021 11:06 am
Profile

Joined: Wed Feb 03, 2021 4:13 am
Posts: 19
Expressions are implemented.
Implemented operators are binary C operators: + - * / % << >> & | ^
They have the same effects and priorities like in C language.
There is no unary operators and I don't want to implement them right now for two reasons: numerical literals can have unary minus already (must not be space-separated!), so there is only unary ~ which I wish right now. But unary ~ X could be rewritten as X ^ $FFFF, so it's not problem.

As was said in the first version of specs expressions in assembler instructions must be enclosed in round brackets. This is because there is no commas in classic syntax:
Code:
    addis r0 r1 ( 10 * ( 20 + 30 ) )

But new 'math' assembler syntax makes this requirement even stronger:
Code:
    r0 = r1 + (10 * (20 + 30))

We need to distinguish '+' as machine instruction from '+' as operator of expression evaluator.
Forward references are possible, but some keywords requires const expressions. These are 'org' and 'ds':
Code:
    org some + 200 ; 'some' must be calculatable in first pass of assembler in this point

A little change to lexem extractor: round and square brackets are considered as 'terminals' and do not require separation spaces and cannot be part of identifiers.

Round brackets are not required during symbol definition:
Code:
symbol1   = end - start ; brackets could be omitted


This must be enough to write complex programs, so it seems like I'm ready to get SDL and emulate videochip design and other hardware. :)


Tue Apr 27, 2021 1:58 pm
Profile
Display posts from previous:  Sort by  
Reply to topic   [ 24 posts ]  Go to page 1, 2  Next

Who is online

Users browsing this forum: No registered users and 3 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB® Forum Software © phpBB Group
Designed by ST Software