All the Things - Nakazoto/Hellorld GitHub Wiki
Hellorld! on All the Things
One of the greatest things about "Hellorld!" is it's really friendly for being displayed on all sorts of interesting displays, even 7-segment LED displays. This page is dedicated to getting all sorts of wild things to show "Hellorld!" Entries are in alphabetical order.
Quick links:
CARDIAC | ENIAC | Fluke DMM | Psion Organiser II LZ |
TI-83 / TI-86 | Tranz 330 Credit Card POS | VMU (Dreamcast) | VTech Genius Leader 4000 |
CARDIAC
CARDIAC is short for CARDboard Illustrative Aid to Computation. It was created by Bell Labs to teach how computers work to school children. I use it in my introductory Computer Science class at Drexel University. For the purposes of Hellorld, the CARDIAC doesn't have textual output, so I have had it output the ASCII codes in decimal form. My CARDIAC page will tell you more than you ever want to know about it.
The assembly language code for Hellorld on the CARDIAC is as follows:
10 130 loop CLA msg
11 320 TAC done
12 530 doout OUT msg
13 110 CLA loop
14 200 ADD 00
15 610 STO loop
16 112 CLA doout
17 200 ADD 00
18 612 STO doout
19 810 JMP loop
20 900 done HRS 00
30 072 msg DATA 72, 101, 108, 108, 111, 114, 108, 100, 33, -1
31 101
32 108
33 108
34 111
35 114
36 108
37 100
38 033
39 -001
Running the code on an online implementation of the CARDIAC results in:
The following is a bootable card deck that can be put into the simulator and run.
002
800
010
130
011
320
012
530
013
110
014
200
015
610
016
112
017
200
018
612
019
810
020
900
030
072
031
101
032
108
033
108
034
111
035
114
036
108
037
100
038
033
039
-001
810
ENIAC
When it comes to Turing-complete machines it's hard to beat the ENIAC for uniqueness. Not only was there only ever one built, but its method of program control was very different from almost everything else. As originally built and used, operation sequencing was determined through patch cable wiring, rather than numerical encoding of instructions. (Later, instruction decoding was implemented on the ENIAC, and that's how it was programmed for most of its life. But that's a story for another time.) This page is where I attempt to document some subset of my trip down the rabbit hole with the ENIAC.
The ENIAC's output mechanism was an off-the-shelf IBM card punch. It was used exclusively for numerical output. For that reason, we are implementing Hellorld in terms of the numerical encodings of the characters. Because EBCDIC evolved from punched card representations of alphanumeric material, it seems the most appropriate encoding to use here. However, it's quite anachronistic, as EBCDIC didn't come into use until about 10 years after the ENIAC was retired.
A view of the simulator after the completion of the Hellorld! run:
A straight-on view of Accumulators 15-18 and Function Tables 2 and 3 after the 'r' character has been read from the function table but before it has been punched:
The programming is shown here in a sort of ENIAC "assembly language" configuration for an ENIAC simulator. Lines beginning with 'p' describe patch cable pluggings, those with 's' specify switch settings, and those with '#' are comments.
#
# Usagi Electric's Hellorld challenge
#
# EBCDIC characters in decimal on the second function table
# Mark the end of the string with a negative value and use the
# sign to determine whether we're continuing or halting.
s f2.mpm1 T
s f2.RA0S P
s f2.RA0L3 2
s f2.RA0L2 0
s f2.RA0L1 0
s f2.RA1S P
s f2.RA1L3 1
s f2.RA1L2 3
s f2.RA1L1 3
s f2.RA2S P
s f2.RA2L3 1
s f2.RA2L2 4
s f2.RA2L1 7
s f2.RA3S P
s f2.RA3L3 1
s f2.RA3L2 4
s f2.RA3L1 7
s f2.RA4S P
s f2.RA4L3 1
s f2.RA4L2 5
s f2.RA4L1 0
s f2.RA5S P
s f2.RA5L3 1
s f2.RA5L2 5
s f2.RA5L1 3
s f2.RA6S P
s f2.RA6L3 1
s f2.RA6L2 4
s f2.RA6L1 7
s f2.RA7S P
s f2.RA7L3 1
s f2.RA7L2 3
s f2.RA7L1 2
s f2.RA8S P
s f2.RA8L3 0
s f2.RA8L2 9
s f2.RA8L1 0
s f2.RA9S M
s f2.RA9L3 0
s f2.RA9L2 0
s f2.RA9L1 1
# Printing lower half of Acc 18
s pr.12 P
# Use the initial pulse to start the ball rolling
p i.Io 1-1
# Set up the data trunks
p 1 f2.arg
p f2.A 1
p a17.A 1
p 1 a18.α
p a18.A 1
# Start a function table lookup
p 1-1 f2.1i
s f2.op1 A0
s f2.cl1 NC
s f2.rp1 1
p f2.NC 1-2
# Transmit the table argument from Acc 17
p 1-2 a17.5i
s a17.op5 A
s a17.cc5 0
s a17.rp5 1
p a17.5o 1-3
# Increment the table argument in parallel with lookup
p 1-3 a17.6i
s a17.op6 ε
s a17.cc6 C
s a17.rp6 1
p a17.6o 1-4
# Clear Acc 18 in parallel with increment and lookup
p 1-3 a18.1i
s a18.op1 0
s a18.cc1 C
# Delay to end of FT loolup
p 1-4 a17.7i
s a17.op7 0
s a17.cc7 0
s a17.rp7 1
p a17.7o 1-5
# Transfer FT output to Acc 18
p 1-5 a18.5i
s a18.op5 α
s a18.cc5 0
s a18.rp5 1
p a18.5o 1-6
# Transmit Acc 18 subtractively. The adapter connects
# the sign to control line 1-7. Because we're transmitting
# subtractively, there will be no pulses for a negative number
# and 9 pulses for a positive number. The pulses are sent
# through a dummy program to synchronize them with the
# central programming pulse and its output triggers the
# printing. Completion of the printing starts the whole cycle
# over again.
p 1-6 a18.6i
s a18.op6 S
s a18.cc6 0
s a18.rp6 1
p a18.S ad.dp.1.11
p ad.dp.1.11 1-7
p 1-7 i.Pi
p i.Po 1-1
Fluke Digital Multimeter
This is my kind of crazy! Getting Hellorld! running on bonkers things is 100% up my alley, but a digital multimeter is taking it to an extreme that makes me smile ear-to-ear. The Fluke 45 is based upon a HD6303Y CPU from Hitachi, has a 16 bit address bus and 8 bit data bus. Hiding out on that address/data bus is a 64kb not-reprogrammable ROM, so Pengi got to work making an adapter to stuff an 8kB AT28C64B EEPROM in place and get the multimeter to do some tricky things.
The whole process is outlined here on Pengi's github..
Code: The code is a couple hundred lines long, and available in its entirety here. Included below is a short excerpt.
...
disp_d:
TSX
LDAB $02,X ; All calls use the same top argument
PSHB
JSR disp_clear_digit
LDAA #1
PSHA
JSR disp_set_segment
PULA
LDAA #2
PSHA
JSR disp_set_segment
PULA
LDAA #3
PSHA
JSR disp_set_segment
PULA
LDAA #4
PSHA
JSR disp_set_segment
PULA
LDAA #6
PSHA
JSR disp_set_segment
PULA
PULB
RTS
...
Psion Organiser II LZ
The Psion Organiser launched in 1984 and was marketed as a full-on pocket computer. The Oragniser 2 shown here was released in 1986 as the successor the Organiser 1. The 2 was rocking an 8-bit Hitachi 6301 family processor, 64kb of battery backed RAM, and datapak support for expansion. The keyboard was “much improved” over the 1 model, but, you know, that still looks daunting. Which is even more impressive that Staven managed to get it to Hellorld! The code is just a string of raw hexadecimal that I have absolutely zero clue what means, but Staven has a Github dedicated to the project with all sorts of wonderful information.
Click here for Staven’s Github on this project.
Code:
CE0000200A48454C4C4F524C44210086193F14A600084D27043F1020F63F4839
TI-83 Plus / TI-86
Oooh, I'm 100% on board for this one! The TI-83 is really a highly specialized Z80 computer, which means it can do computery things, like print "Hellorld!" Which is exactly what stamasd over on the Discord did. After ordering a cable and a bit of code tweaking, stamasd was able to upload the assembled code and execute it on the real deal hardware, proving that even calculators can "Hellorld!" in style! But, they didn't stop there, stamasd got on a roll and managed to get it working on a TI-86 as well, absolutely epic!
TI-83 Plus Code:
.NOLIST
#define bcall(xxxx) rst 28h \ .dw xxxx
_newline .equ 452Eh
_PutS .equ 450Ah
_ClrLCDFull .equ 4540h
.LIST
.org 9D93h
.db $BB,$6D
ld a,0
bcall(_ClrLcdFull)
ld hl,tx1
bcall(_NewLine)
bcall(_PutS)
ld hl,tx2
bcall(_NewLine)
bcall(_PutS)
bcall(_NewLine)
ret
tx1:
.db "Hellorld!",0
tx2:
.db "Courtesy of Z80",0
.end
.end
TI-86 Code:
_asm_exec_ram .equ 0D748h
_clrLCD .equ 4A7Eh
_curRow .equ 0C00Fh
_curCol .equ 0C010h
_puts .equ 4A37h
_getkey .equ 55AAh
.org _asm_exec_ram
call _clrLCD
ld a,0
ld (_curRow),a
ld a,0
ld (_curCol),a
ld hl,hellorld
call _puts
call _getkey
ret
hellorld: .db "Hellorld!",0
.end
.end
Tranz 330 Credit Card Machine
The Tranz 330 is a Zilog Z80 based credit card terminal that uses standard Z80 peripherals and is very hacker friendly. As of 2023 these are still plentiful and cheap on the used market. I absolutely love seeing things like this get hacked for hilarious purposes. The Z80 is a wonderful little processor, and it makes perfect sense to use it in something like a Point of Sale device. But, being Z80 makes it perfect for "Hellorld!", which Andrew did and I absolutely adore it!
In the code below, spaces and newlines were eliminated to make it as compact as possible for display here. The full code, with comments, as well as information on how to implement is available on Andrew's Github at this link.
Code:
; Barebones program to write to the Tranz 330 VFD
; 2023 by Andrew Litt
.ORG $0000
PIO_A_DAT .EQU $00
PIO_A_CON .EQU $01
STACK .EQU $9000 ; seems like a decent place...
RST:
DI ;interrupts stay off
LD HL, STACK ; set up stack though we don't use it
LD SP, HL
LD A, $CF ; enter PIO_A bit mode (3)
OUT (PIO_A_CON), A ; next byte must be I/O direction
LD A, $80 ; All outputs except bit 7
OUT (PIO_A_CON), A
LD A, $07 ; disable PIO interrupts
OUT (PIO_A_CON), A ; next byte must be GPIO int mask
LD A, $FF ; PIO int mask (redundant)
OUT (PIO_A_CON), A
LD A, $3F ; initial GPIO port state
OUT (PIO_A_DAT), A
LD A, $2F ; assert display reset
OUT (PIO_A_DAT), A
LD B, $30 ; display reset hold time
VFD_RST_WAIT:
DJNZ VFD_RST_WAIT
LD A, $3F ; deassert reset
OUT (PIO_A_DAT), A
LD HL, PAYLOAD
STRING_SEND_LOOP:
LD A, (HL) ; test if the current string char is zero
OR A
JR Z, INFINITY
LD C, A
LD B, $08 ; 8 bits to xfer, MSB first
BIT_SEND_LOOP:
IN A, (PIO_A_DAT) ; get current port state
AND A, $9F ; mask off the CLK and DAT bits
RLC C ; rotate left w/ MSb into carry
JR NC, BIT_IS_ZERO ; if the MSb is zero, skip setting it
OR A, $20 ; MSb is one, set the DAT bit to match
BIT_IS_ZERO:
OUT (PIO_A_DAT), A ; data setup with CLK low
OR A, $40 ; toggle CLK high
OUT (PIO_A_DAT), A
AND A, $BF ; toggle CLK low
OUT (PIO_A_DAT), A
DJNZ BIT_SEND_LOOP ; next bit
INC HL ; next byte
JP STRING_SEND_LOOP
INFINITY:
JP INFINITY
PAYLOAD:
.BYTE $FF ; display to max brightness
.BYTE $AF ; cursor to beginning of line
.BYTE " HELLORLD ",0
Visual Memory Unit (Dreamcast)
The SEGA Dreamcast was a pretty righteous little game console, I remember being beyond hyped about Phantasy Star Online on the Dreamcast, but one of the coolest things about the Dreamcast was the memory card. It plugged into the controller, but it was so, so much more than a memory card. It was a full-fledged handheld game console by itself! It had an 8-bit Sanyo LC8670 CPU, a monochrome LCD, multiplayer gaming capability, second functionality, a real-time clock, file manager, 100KB of flash memory, and sound capability. All that in a memory card, absolutely bonkers!
But, can it "Hellorld"? Not easily. Fortunately, user insize over on the Discord is on the case! A lot of this is over my head, so I'll paraphrase here:
"The VMU has got only a bitmap so I had to program my own font engine. It's monospace to keep things simple but it still ended up getting pretty big. The font is encoded as Shift-JIS because it's the same that the VMU and Dreamcast use internally, it's a mix of Japanese characters with normal English ones (ASCII). The program first initializes the register and clears the screen to all zeroes. Then it enters the main loop to execute the print characters function. 'Print characters' gets called, and it first clears out some RAM to use as a buffer, and then initializes a few temporary registers. Then begins the print loop. First it takes a character from the string you fed it, then checks its value to see if it matches these ranges: 0x20 trough 0x80 for English characters or 0xA0 trough 0xE0 Japanese characters. If either fail it "prints" a blank char (skips the process and goes to the next char). Then it checks if the print position is odd or even, and if it's odd it has to shift the character 4 pixels to the right because the screen is encoded with the good ol' horizontal bytes. It then masks the new character, stores it into the buffer and moves to the next character in the string. When the whole procedure is done it copies the buffer into the main screen RAM and stalls the CPU."
The font engine is available at this link.
Below is just an excerpt of the code, the full code can be found at this link.
...
; /////////////////////////////////////////////////////////////
; /// SUBROUTINES ///
; /////////////////////////////////////////////////////////////
PrintStringFlash:
; r2 and XBNK = XRAM location (make sure even line)
; temp1 = char count
; temp2 = flash address low
; temp3 = flash address high
; initialize WRAM
ld temp1
clr1 PSW, 7
rorc
addc #0
st 1
call ClearCharCellsWRAM
; render text
ld temp1
st 1
mov #0, chptr
.StringLoop:
ld temp2
st TRL
ld temp3
st TRH
ldf
call DrawChar
inc temp2
ld temp2
bnz .NoCarry
inc temp3
.NoCarry:
dbnz 1, .StringLoop
; copy result
ld temp1
clr1 PSW, 7
rorc
addc #0
st 1
call PrintCharCells
ret
...
VTech Genius Leader 4000 (aka. PreComputer)
The "Genius Leader" is a line of Z80 based learning computers, known in the US as "PreComputer". If an (E)EPROM contains the correct signature, the machine happily executes any Z80 code you throw at it. This "hellorld!" does not use firmware ROM syscalls to display the text, but instead communicates with the LCD controller directly. That's why the code must include the whole HD44780 initialization code.
For the sake of simplicity, the text is written to the middle of the screen, without taking care of the display segmentation. That's why the exclamation mark appears on a different line - it crosses the display RAM segment boundary...
Code:
This code should also work on the GL2000 series (2-line LCD) or even PreComputer 1000 (1-line LCD) if the LCD offset (LCD_SETDDRAMADDR) and autostart signature are altered accordingly.
; "Hellorld!" for VTech Genius Leader 4000 Quadro aka. PreComputer
org 08000h
; VTech cartridge header
.db #0x55
.db #0xaa
; "Normal" signature (i.e. non-autostart program cartridge)
;.db #0x47 ; "G"
;.db #0x41 ; "A"
; "Auto-start" signature for PreComputer1000
;.db #0x33 ; 0x33 = autostart jump to 0x8010
;.db #0x00 ; Dont care
; "Auto-start" signature for GL2000/4000/6000
.db #0x59 ; "Y"
.db #0x45 ; "E"
; End of cartridge header
di ; Disable interrupts
ld sp, #0xdff0 ; Load Stack Pointer near top of RAM
jp main
; LCD support functions
lcd_delay:
push hl
ld hl,0010fh ; Delay length
loop_lcd_delay:
dec l
jr nz,loop_lcd_delay
dec h
jr nz,loop_lcd_delay
pop hl
ret
lcd_write_control:
out (00ah),a ; Write to LCD control register/port
call lcd_delay ; Delay long...
call lcd_delay ; ...by delaying twice
ret
lcd_write_data:
out (00bh),a ; Write to LCD data register/port
call lcd_delay ; Delay a bit
ret
lcd_init:
; Initialize the HD44780 LCD controller
; Enter 8 bit mode by sending 0x38 four times
ld a,038h ; 0x38 = Function set: 2 Line, 8-bit, 5x7 dots
call lcd_write_control
call lcd_write_control
call lcd_write_control
call lcd_write_control
; Clear screen
ld a,001h
call lcd_write_control
; Set cursor/insert mode
ld a,00fh ; LCD_DISPLAYCONTROL | LCD_DISPLAYON | LCD_CURSORON | LCD_BLINKON
call lcd_write_control
ld a,006h ; LCD_ENTRYMODESET | LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT
call lcd_write_control
ret
; Main function
main:
call lcd_init
; Start output at a continuous part of VRAM around the center of the screen
ld a,0c8h ; LCD_SETDDRAMADDR | 72
call lcd_write_control
; Start at beginning of string
ld hl,str_hello
; Print loop
loop_print:
ld a,(hl) ; Load next char
or a ; Check if it is zero
jr z,loop_halt ; If it is: Jump to end of loop
call lcd_write_data
inc hl
jr loop_print
; End of print loop
loop_halt:
jr loop_halt ; Loop forever
; Data
str_hello:
.ascii "Hellorld!"
.db 0x00 ; Zero-termination
A SDCC based SDK for those machines is available on HotKey's Github.