PDA

View Full Version : Kenbak-1 demo program.


Geoff Harrison
10-08-2007, 08:23 PM
Well, I finally got tired of watching the Kanbak-1 counting to 255 in binary, so I wrote a little program to do a Cylon display on the LEDs instead.

Change the value at 034 to change the speed.


Addr Value
---- ---------
; Display Cylon lights on the Kenbak-1 front panel
003 004
004 023 001 START LOAD A, #1 ; A = 00000001b
006 034 200 LEFT STORE A, 0200 ; display A on LEDs
010 367 032 JMD WAIT ; pause
012 211 LEFT SHIFT A 1 ; A << 1
013 043 006 JPD A!=0, LEFT ; if A != 0 jump to label LEFT
;
015 023 200 LOAD A, #0200 ; A = 10000000b
017 034 200 RIGHT STORE A, 0200 ; display B on LEDs
021 367 032 JMD WAIT ; pause
023 011 RIGHT SHIFT A 1 ; A >> 1
024 323 177 AND A, #0177 ; mask off sign bit
026 043 017 JPD A!=0, RIGHT ; if A != 0 jump to label RIGHT
030 347 004 JPD START ; repeat forever
;
032 000 WAIT .equ 0 ; return address will be stored here
033 123 020 LOAD B, #020 ; delay for a count of 020
035 113 001 WAIT1 SUB B, #1 ; decrement B
037 143 035 JPD B!=0, WAIT1 ; if B != 0 jump to label WAIT1
041 357 032 JPI WAIT ; return

Grant Stockly
10-09-2007, 05:55 AM
Looks like you're having fun! Isn't it amazing, that a pile of TTL chips is 'thinking'? These are the chips that we normally use to support an Altair or Apple II!

I still can't get over it. :)

Didn't some cylons have two dots that meet each other in the middle. Will that be version 2? :)

phe
10-09-2007, 12:57 PM
Excellent idea for a program. I'll have to try to replicate it on the 8800.

This is interesting code to read. JMD must be like a CALL. I can't figure out how the WAIT subroutine returns. Does the Kenbak have a stack? Where is the equivalent "RET" instruction?

Paul

Geoff Harrison
10-09-2007, 01:48 PM
Does the Kenbak have a stack? Where is the equivalent "RET" instruction?
Paul

No, no stack on a Kenbak. The JMD (Jump and Mark Direct) instruction stores the value {program counter}+2 at the address in the operand, then jumps to the address {operand}+1. To return you do an unconditional JPI (Jump Indirect) using the start of the subroutine as the operand, which returns you to the instruction following the JMD. It's all pretty neat but it means you can't do recursion, of course :)

Geoff Harrison
10-09-2007, 02:57 PM
Didn't some cylons have two dots that meet each other in the middle. Will that be version 2? :)

OK, here's another version using indexed mode. It's easier to change the pattern in this one by just changing the table


Addr Value
---- ---------
; Display Cylon lights on the Kenbak-1 front panel
; Version 2
003 004 ; initialize PC
004 223 000 START LOAD X, #0 ; X = 0
006 026 033 LOOP LOAD INDEX A, TABLE ; set A = next byte from table
010 044 004 JPD A=0, START ; restart if at end of tale
012 034 200 STORE A, 0200 ; display A on LEDs
014 367 022 JMD WAIT ; pause
016 203 001 ADD X, #1 ; decrement X
020 347 006 JPD LOOP ; loop to get next pattern
;
022 000 WAIT .equ 0 ; return address will be stored here
023 123 020 LOAD B, #020 ; delay for a count of 020
025 113 001 WAIT1 SUB B, #1 ; decrement B
027 143 025 JPD B!=0, WAIT1 ; if B != 0 jump to label WAIT1
031 357 022 JPI WAIT ; return
;
033 201 TABLE .equ 10000001
034 102 .equ 01000010
035 044 .equ 00100100
036 030 .equ 00011000
037 044 .equ 00100100
040 102 .equ 01000010
041 201 .equ 10000001
042 000 .equ 00000000



Isn't it amazing, that a pile of TTL chips is 'thinking'?


Yes. I'm almost glad I missed that solder joint, the time I spent looking over the circuit diagrams and state diagrams gave me a good appreciation for John's interesting design. I find some of the Kenbak's quirks quite interesting: the serial architecture of course, the lack of a stack, the variable execution time of the instructions, the accessibility of the registers as memory locations (though some other CPUs do that too).

Does anyone know of other machines that use a serial design like this one?

Geoff.

Grant Stockly
10-10-2007, 07:16 AM
016 203 001 ADD X, #1 ; decrement X

increment X?

Geoff Harrison
10-10-2007, 12:39 PM
increment X?

Oops. Also, why didn't I do the pause in line this time instead of as a subroutine? Oh well.

I'm still writing these little routines directly in machine language and then back filling the assembly code and comments later, which is why the assembly code has inconsistent syntax. I need to switch to writing in assembly and standardize the code; can I download your patches to as? Also, do you have the datasheets for the 1404 shift registers? I haven't been able to find much information about them.

Grant Stockly
10-11-2007, 07:58 AM
I'll just gzip my whole project folder after a make-clean. There are dozens of patches in random areas to get everything to work just right (like octal listing output)

You'll have to modify the makefile.

I'll try to do this by the weekend.

Grant Stockly
10-13-2007, 10:22 PM
Following Geoff's hand code is the code required for the KENBAK-1 AS assembler.



Addr Value
---- ---------
; Display Cylon lights on the Kenbak-1 front panel
; Version 2
003 004 ; initialize PC
004 223 000 START LOAD X, #0 ; X = 0
006 026 033 LOOP LOAD INDEX A, TABLE ; set A = next byte from table
010 044 004 JPD A=0, START ; restart if at end of tale
012 034 200 STORE A, 0200 ; display A on LEDs
014 367 022 JMD WAIT ; pause
016 203 001 ADD X, #1 ; decrement X
020 347 006 JPD LOOP ; loop to get next pattern
;
022 000 WAIT .equ 0 ; return address will be stored here
023 123 020 LOAD B, #020 ; delay for a count of 020
025 113 001 WAIT1 SUB B, #1 ; decrement B
027 143 025 JPD B!=0, WAIT1 ; if B != 0 jump to label WAIT1
031 357 022 JPI WAIT ; return
;
033 201 TABLE .equ 10000001
034 102 .equ 01000010
035 044 .equ 00100100
036 030 .equ 00011000
037 044 .equ 00100100
040 102 .equ 01000010
041 201 .equ 10000001
042 000 .equ 00000000




; Display Cylon lights on the Kenbak-1 front panel
; Version 2
; By Geoff Harrison
; Syntax and AS conversion by Grant Stockly
cpu KENBAK ; Assemble for the KENBAK
include kenbak.inc ; Kenbak include file
relaxed on ; Allow non-intel constant formats
;
ORG 003o ; Location of PC Register
DB 004o ; Example on how to "setup" PC Register
;
ORG 004o ; First non-special address
;
START: LDC X, 0 ; Load constant 0 to X
LOOP: LDX A, TABLE ; set A = next byte from table
JDZ A, START ; restart if at end of table
STM A, Lamps ; display A on LEDs
JMMD WAIT ; pause
ADC X, 1 ; increment X
JMP LOOP ; loop to get next pattern
;
WAIT: DB 0 ; return address will be stored here
LDC B, 020o ; delay for a count of 020
WAIT1: SBC B, 1 ; decrement B
JDNZ B, WAIT1 ; if B != 0 jump to label WAIT1
JMI WAIT ; return
;
TABLE: DB 0b10000001 ;
DB 0b01000010 ;
DB 0b00100100 ;
DB 0b00011000 ;
DB 0b00100100 ;
DB 0b01000010 ;
DB 0b10000001 ;
DB 0b00000000 ;
;
;END

I'm not too happy with the listing output. I will have to figure out what to do. Do you guys think the listing is OK with all of the (MACRO) lines? I guess it is helpful to know what your code expands to...

You may notice some differences between the assembled code and Geoff's hand code. John used the condition "Zero" when "Unconditional" was specified. Geoff used "Positive Non-Zero", but this difference should not affect the operation of the code. My kenbak is still in pieces from scanning the motherboard. Geoff, can you key in this version of the cylon program and see if it works?

I'll try to have the online assembler going soon... :)

Here is the assembled code:
AS V1.42 Beta [Bld 55] - source file cylon2.asm - page 1 - 10/13/2007 14:14:28


1/ 0 : ; Display Cylon lights on the Kenbak-1 front panel
2/ 0 : ; Version 2
3/ 0 : ; By Geoff Harrison
4/ 0 : ; Syntax and AS conversion by Grant Stockly
5/ 000 : cpu KENBAK ; Assemble for the KENBAK
6/ 000 : ;macexp off ; Turn off macro expansion
7/ 000 : include kenbak.inc ; Kenbak include file
(1) 439/ 000 : listing on
8/ 000 : relaxed on ; Allow non-intel constant formats
9/ 000 : ;
10/ 003 : ORG 003o ; Location of PC Register
11/ 004 : 004 DB 004o ; Example on how to "setup" PC Register
12/ 004 : ;
13/ 004 : ORG 004o ; First non-special address
14/ 004 : ;
15/ 004 : (MACRO) START: LDC X, 0 ; Load constant 0 to X
15/ 006 : 223 000 LOAD Immediate, X, 0
16/ 006 : (MACRO) LOOP: LDX A, TABLE ; set A = next byte from table
16/ 010 : 026 033 LOAD Indexed, A, TABLE
17/ 010 : (MACRO) JDZ A, START ; restart if at end of table
17/ 012 : 044 004 JMPD A, Zero, START
18/ 012 : (MACRO) STM A, Lamps ; display A on LEDs
18/ 014 : 034 200 STORE Memory, A, LAMPS
19/ 014 : (MACRO) JMMD WAIT ; pause
19/ 016 : 364 022 JMPMD Unconditional, Zero, WAIT
20/ 016 : (MACRO) ADC X, 1 ; increment X
20/ 020 : 203 001 ADD Immediate, X, 1
21/ 020 : (MACRO) JMP LOOP ; loop to get next pattern
21/ 022 : 344 006 JMPD Unconditional, Zero, LOOP
22/ 022 : ;
23/ 023 : 000 WAIT: DB 0 ; return address will be stored here
24/ 023 : (MACRO) LDC B, 020o ; delay for a count of 020
24/ 025 : 123 020 LOAD Immediate, B, 020O
25/ 025 : (MACRO) WAIT1: SBC B, 1 ; decrement B
25/ 027 : 113 001 SUB Immediate, B, 1
26/ 027 : (MACRO) JDNZ B, WAIT1 ; if B != 0 jump to label WAIT1
26/ 031 : 143 025 JMPD B, Non_Zero, WAIT1
27/ 031 : (MACRO) JMI WAIT ; return
27/ 033 : 354 022 JMPI Unconditional, Zero, WAIT
28/ 033 : ;
29/ 034 : 201 TABLE: DB 0b10000001
30/ 035 : 102 DB 0b01000010
31/ 036 : 044 DB 0b00100100
32/ 037 : 030 DB 0b00011000
33/ 040 : 044 DB 0b00100100
34/ 041 : 102 DB 0b01000010
35/ 042 : 201 DB 0b10000001
36/ 043 : 000 DB 0b00000000
37/ 043 :
38/ 043 : ;END
symbol table (* = unused):
------------------------

A : 0 - | *ARCHITECTURE : i386-unknown-win32 - |
B : 1 - | *BIGENDIAN : 0 - |
*BRANCHEXT : 0 - | *CASESENSITIVE : 0 - |
*CONSTANT : 3 - | *CONSTPI : 3.141592653589793 - |
*DATE : 10/13/2007 - | *DEF : 5 - |
*DEFERRED : 5 - | *FALSE : 0 - |
*FOUR : 4 - | *FOUR_PLACES : 4 - |
*FULLPMMU : 1 - | *HAS64 : 1 - |
*HASDSP : 0 - | *HASFPU : 0 - |
*HASPMMU : 0 - | *IMM : 3 - |
IMMEDIATE : 3 - | *IND : 5 - |
INDEXED : 6 - | *INDIND : 7 - |
*INDIRECT : 5 - | *INEXTMODE : 0 - |
*INIX : 7 - | *INLWORDMODE : 0 - |
*INMAXMODE : 0 - | *INPUT : FF - |
*INSRCMODE : 0 - | *INSUPMODE : 0 - |
*INX : 6 - | *L : 2 - |
LAMPS : 80 - | *LEFT : 2 - |
*LISTON : 1 - | LOOP : 6 C |
*MACEXP : 1 - | *MEM : 4 - |
MEMORY : 4 - | *MOMCPU : EBA - |
*MOMCPUNAME : KENBAK - | *NEG : 5 - |
*NEGATIVE : 5 - | *NESTMAX : 100 - |
NON_ZERO : 3 - | *NZR : 3 - |
*ONE : 1 - | *ONE_PLACE : 1 - |
*OUTPUT : 80 - | *PACKING : 0 - |
*PADDING : 1 - | *PC : 3 - |
*PNZ : 7 - | *POSITIVE_NON_ZERO : 7 - |
*POSITIVE_OR_ZERO : 6 - | *POZ : 6 - |
*R : 0 - | *REGA : 0 - |
*REGB : 1 - | *REGISTERA : 0 - |
*REGISTERB : 1 - | *REGISTERPC : 3 - |
*REGISTERX : 2 - | *REGPC : 3 - |
*REGX : 2 - | *RELAXED : 1 - |
*RIGHT : 0 - | *SA : 81 - |
*SB : 82 - | *STAA : 81 - |
*STAB : 82 - | START : 4 C |
*STATUSA : 81 - | *STATUSB : 82 - |
*STATUSX : 83 - | *STAX : 83 - |
*SWITCHES : FF - | *SX : 83 - |
TABLE : 1B C | *THREE : 3 - |
*THREE_PLACES : 3 - | *TIME : 14:14:28 - |
*TRUE : 1 - | *TWO : 2 - |
*TWO_PLACES : 2 - | *UNCND : 3 - |
UNCONDITIONAL : 3 - | *VERSION : 142F - |
WAIT : 12 C | WAIT1 : 15 C |
X : 2 - | ZERO : 4 - |
*ZRO : 4 - |

95 symbols
80 unused symbols

defined macros:
---------------

ADC | ADI
ADIX | ADM
ADX | ANC
ANI | ANIX
ANM | ANX
CBR | CLR
DEC | HLT
INC | JDN
JDNZ | JDP
JDPZ | JDZ
JIN | JINZ
JIP | JIPZ
JIZ | JMI
JMMD | JMMI
JMP | JUMP
LDC | LDI
LDIX | LDM
LDX | LNC
LNI | LNIX
LNM | LNX
LSL | LSR
MDN | MDNZ
MDP | MDPZ
MDZ | MIN
MINZ | MIP
MIPZ | MIZ
NOP | ORC
ORI | ORIX
ORM | ORX
ROL | ROR
SBC | SBI
SBIX | SBM
SBR | SBRC
SBRS | SBX
SER | STC
STI | STIX
STM | STX

74 macros

codepages:
----------

STANDARD (0 changed characters)


0.03 seconds assembly time

477 lines source file
488 lines incl. macro expansions
2 passes
0 errors
0 warnings

Geoff Harrison
10-13-2007, 11:42 PM
You may notice some differences between the assembled code and Geoff's hand code. John used the condition "Zero" when "Unconditional" was specified. Geoff used "Positive Non-Zero", but this difference should not affect the operation of the code. My kenbak is still in pieces from scanning the motherboard. Geoff, can you key in this version of the cylon program and see if it works?


Yep, it works fine.

The only reason I used Positive Non-Zero on the unconditional jump was because the last 3 bits of the instruction must not be less than 003, so I just set them to 007. Any value 003 or greater will work.