I'm an open source nerd and I'm messing around with making a SUBLEQ computer from 74XX components.
This user joined on 05/12/2021.
RIUM+ (Mike Ando)
Create an account to leave a comment.
Already have an account?
16 bit is 64kb, assuming standard SubLEq. Yeah okay, I am over the top with my statement.
Still SubLEq is incredibly inefficient (i.e. super low code density).
Here are my results:
* 12 lines of high level language coverts to* 74 lines of OpCodes (95 words), which converts to* 3126 lines of Subleq including comments (5530 words).
This resulted in very slow execution.
Here is the code (in PL/0):
A=4; B=1; if A<B then write A*10<b; else begin write 1<B*10; write B*10, (a+b)*-5; end C=-1; write C; end
Are you sure? yes | no
16 bit is 65,536 addresses, which is indeed 64KiB for byte addressable memory, but my design uses word addressable memory (two bytes per address), thus 128KiB.
Those results are interesting, indeed shows extremely poor code density; did you write the SUBLEQ program by hand, or was it generated by a compiler? I'm wondering if maybe the compiler was responsible for the low performance; I'd bargain that program could be written in 100 instructions or less.
About 4 years ago (so my memory is a bit faded) I wrote a PL/0 compiler (which produces pcode) . Then I wrote a pcode assembler that exports SubLEq. And then a SubLEq interpreter.
Well that is a challenge! 100 instructions!
When you get into SubLEq you will need to set up a "system", which contains useful variables and constants, and code for indirect move (which using self modifying code, unless you opt for SubLEq+). In my case that used 210 bytes (70 instructions).
I can post my system later if you like.
Here is the PCode for the 12 line of code above:
Simple OpCode: 0: movAxImm 4 2: movVarAx 49152 4: movAxImm 1 6: movVarAx 49153 8: movAxVar 49152 10: pushAx 0 11: movAxVar 49153 13: movBxAx 0 14: popAx 0 15: cmpBx 0 16: setLT 0 17: orAxAx 0 18: jz 38 20: movAxVar 49152 22: pushAx 0 23: movAxImm 10 25: popBx 0 26: mulBx 0 27: pushAx 0 28: movAxVar 49153 30: movBxAx 0 31: popAx 0 32: cmpBx 0 33: setLT 0 34: wrtAx 0 35: wrtLn 0 36: jmp 81 38: movAxImm 1 40: pushAx 0 41: movAxVar 49153 43: pushAx 0 44: movAxImm 10 46: popBx 0 47: mulBx 0 48: movBxAx 0 49: popAx 0 50: cmpBx 0 51: setLT 0 52: wrtAx 0 53: wrtLn 0 54: movAxVar 49153 56: pushAx 0 57: movAxImm 10 59: popBx 0 60: mulBx 0 61: wrtAx 0 62: movAxVar 49152 64: pushAx 0 65: movAxVar 49153 67: popBx 0 68: addBx 0 69: pushAx 0 70: xorAxAx 0 71: pushAx 0 72: movAxImm 5 74: movBxAx 0 75: popAx 0 76: subBx 0 77: popBx 0 78: mulBx 0 79: wrtAx 0 80: wrtLn 0 81: xorAxAx 0 82: pushAx 0 83: movAxImm 1 85: movBxAx 0 86: popAx 0 87: subBx 0 88: movVarAx 49154 90: movAxVar 49154 92: wrtAx 0 93: wrtLn 0 94: halt 0
Then I substituted subleq for each PCode.
I acknowledge I did not use a library, the code was duplicated each time.
Here is the SubLEq code for PCode 26: above:
; imul Ax = Ax * Bx ; jump BEGINf Z Z BEGINf; store immediate value .sgn 1.sgn 1; store immediate value .res 0.res 0; store immediate value .word 1.word 1; Set label BEGIN:BEGIN: ; jgez Test: Ax Jump: ENDIFf T T ? T Ax L1f T T ENDIFfL1: Ax T L2f T T L3fL2: P T ENDIFf T T L3f L3: ; Ax = chs Ax T T ? Ax T ? T Z ? Ax Ax ? Z Ax ? Z Z ? ; sgnb = chs sgnb T T ? sgnb T ? T Z ? sgnb sgnb ? Z sgnb ? Z Z ?; Set label ENDIF:ENDIF: ; jgez Test: Bx Jump: ENDIFf T T ? T Bx L1f T T ENDIFfL1: Bx T L2f T T L3fL2: P T ENDIFf T T L3f L3: ; Bx = chs Bx T T ? Bx T ? T Z ? Bx Bx ? Z Bx ? Z Z ? ; sgnb = chs sgnb T T ? sgnb T ? T Z ? sgnb sgnb ? Z sgnb ? Z Z ?; Set label ENDIF:ENDIF:; Set label LOOP:LOOP: ; resb = shl resb T T ? resb T ? T resb ? ; jgez Test: resb Jump: ENDIFf T T ? T resb L1f T T ENDIFfL1: resb T L2f T T L3fL2: P T ENDIFf T T L3f L3: ; copy resb = _MIN T T ? resb resb ? _MIN T ? T resb ? ; jump ERRORf Z Z ERRORf; Set label ENDIF:ENDIF: ; Ax = shl Ax T T ? Ax T ? T Ax ? ; jgez Test: Ax Jump: ENDIFf T T ? T Ax L1f T T ENDIFfL1: Ax T L2f T T L3fL2: P T ENDIFf T T L3f L3: ; sub Ax = Ax - _MIN _MIN Ax ? ; add resb = resb + Bx T T ? Bx T ? T resb ? ; jgez Test: resb Jump: ENDIFf T T ? T resb L1f T T ENDIFfL1: resb T L2f T T L3fL2: P T ENDIFf T T L3f L3: ; copy resb = _MIN T T ? resb resb ? _MIN T ? T resb ? ; jump ERRORf Z Z ERRORf; Set label ENDIF:ENDIF: ; wordb = shl wordb T T ? wordb T ? T wordb ? ; wordb = inc wordb N wordb ? ; jgtz Test: wordb Jump: LOOPb T T ? T wordb L1f T T LOOPbL1: wordb T L2f T T L3fL2: P T L3f T T L3f L3: ; jgez Test: sgnb Jump: ENDIFf T T ? T sgnb L1f T T ENDIFfL1: sgnb T L2f T T L3fL2: P T ENDIFf T T L3f L3: ; resb = chs resb T T ? resb T ? T Z ? resb resb ? Z resb ? Z Z ?; Set label ENDIF:ENDIF:; Set label ERROR:ERROR: ; copy Ax = resb T T ? Ax Ax ? resb T ? T Ax ?; Set label END:END:
I count 111 lines of actual code.
I am not trying to put you off SubLeq, just that the language is horrible.
I am happy to pass on my subleq macros (which you will need at some point).
Hi Katherine, thanks for the follow.
I see that you are looking at a SubLEQ CPU as well.
I have TinaTI model for my attempt that may be useful to you. TinaTI can be used to test your CPU design, but it is far from ideal.
Anyway, my finding was that a 16 bit SubLEQ was not big enough to create a stand alone programmable demonstration computer!
SubLEQ is also the most horrible language to program in.
PM me if you want to know more about my project.
Anyway best of luck with your project.
Thanks! I'm curious as to how 16 bits might not be enough; using word addressable memory, that's 128KiB, or ~44,000 instructions, which seems like plenty to me!
Create your Hackaday.io profile like Katherine Peeters and many others
© 2021 Hackaday
You are about to report the user "Katherine Peeters", please tell us the reason.