ESP32-S3 Bench Guide
ESP32-S3 N16R8 bench guide: live pinout, lessons, simulators and the bench log.
Altair 8800 emulator in your browser: a working front panel, an Intel 8080, an ASR-33 Teletype and Microsoft's original 4K BASIC
EducationJavaScript · CSSGitHub @wixetteOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Loading the full README. The saved excerpt is shown below.
The 1975 computer that started the personal computer revolution, in
your browser. Toggle 8080 machine code in through a working front
panel, watch it run on the lamps, then install a memory board and boot
Microsoft's original 4K BASIC on a simulated Teletype.
▶ Try it online, with
nothing to install.
The route through it:
1. Try it →
2. The front panel →
3. A program by hand →
4. Around the simulator →
5. The Teletype →
6. 4K BASIC →
7. More programs →
8. For developersRead the full README ↗The 1975 computer that started the personal computer revolution, in your browser. Toggle 8080 machine code in through a working front panel, watch it run on the lamps, then install a memory board and boot Microsoft's original 4K BASIC on a simulated Teletype - or write your own programs in Intel's 8080 assembly language, and assemble them straight into memory.
▶ Try it online, with nothing to install.
The route through it: 1. Try it → 2. The front panel → 3. A program by hand → 4. Around the simulator → 5. The Teletype → 6. 4K BASIC → 7. Assembly → 8. More programs → 9. For developers
A pattern now walks across the data lamps, D7–D0. That is a real program: eight bytes of 8080 machine code, running at the Altair's own 2 MHz. Click STOP to stop it.
The Altair 8800 had no screen and no keyboard. This panel was the whole of the way in and out.
The lamps show the machine as it is:
| Lamps | Show |
|---|---|
| A15–A0 | The address bus: the memory address the CPU is at |
| D7–D0 | The data bus: the byte at that address |
| STATUS, WAIT | What the CPU is doing. WAIT is lit while it is stopped, and HLTA too when a HLT stopped it |
| INTE | Interrupts are enabled: lit by EI, put out by DI and RESET |
| PROT | The memory board at the address shown is protected |
The switches are how you talk to it:
| Switch | What it does |
|---|---|
| OFF/ON | Power. Memory comes up full of random bytes, as on the real one |
| A15–A0 | An address, up for 1 and down for 0. A7–A0 is also the byte to store. Programs can read A15–A8 as the sense switches |
| EXAMINE · EXAMINE NEXT | Show the byte at the address on the switches · at the next address |
| DEPOSIT · DEPOSIT NEXT | Store A7–A0 at the address shown · at the next address |
| RESET · CLR | Send the CPU back to 0000H · clear the serial boards, dropping keys typed and not yet read |
| RUN · STOP | Run the program from where the CPU is · stop it |
| SINGLE STEP | Run one instruction |
| PROTECT · UNPROTECT | Protect the memory board at the address shown (EXAMINE an address on it first), so that neither DEPOSIT nor a program can change it · unprotect it. Each 4 KB board has its own; everything starts unprotected |
| AUX | Nothing: MITS left both spare, for boards added later |
The switches come in groups of three because 8080 programmers wrote
bytes in octal: 00 111 010 is 072 octal, or 3AH. Click the panel's
own switches, or the large buttons on the strip under it, which are
easier to hit and show which switches are up. The small arrow on the
strip's top edge folds it away.
One simplification. SINGLE STEP here always runs one whole instruction, as the Altair's Operator's Manual describes it. The circuit itself, MITS's Theory of Operation says, stopped after each machine cycle, so one instruction could take up to five presses. Stopping only between instructions keeps a step about the program rather than the bus. It also means the STATUS lamps always show the CPU about to fetch its next instruction - MEMR, M1 and WO - or, after a HLT, MEMR, HLTA and WO. INP, OUT and STACK belong to cycles inside an instruction, so they stay dark; and while a program runs the lamps hold still, rather than glowing with every cycle as the real ones did.
This is how an Altair owner put in a program in 1975: one byte at a time, on the switches. It adds 1 and 2. The same steps are in the simulator's Tutorial, under the panel, to follow as you go.
LDA 0080H ; 00 111 010
; 10 000 000
; 00 000 000
MOV B,A ; 01 000 111
LDA 0081H ; 00 111 010
; 10 000 001
; 00 000 000
ADD B ; 10 000 000
STA 0082H ; 00 110 010
; 10 000 010
; 00 000 000
JMP 0000H ; 11 000 011
; 00 000 000
; 00 000 000
At step 18 the panel looks like the picture in section 2: A7 and A1 lit for the address 0082H, and D1 and D0 for the answer.
Everything is on one screen: the panel, a toolbar above it, a dock of tools below it, and a status line along the foot.
The Debugger is a view the real Altair never had. Step through a program with SINGLE STEP and watch it work:
LDA a16,
MVI B,d8), and the operand's value this time.3e8cd3ff fills four in a row; the arrow keys move, and
Esc stops. A protected board refuses, as it refuses DEPOSIT.The Altair's terminal was a Teletype ASR-33: a keyboard and a printer on paper, upper case only. Here it sits on an 88-SIO serial board, at ports 00H and 01H (and an 88-2SIO at 10H and 11H). Nothing echoes by itself: a program has to be running and reading the board.
Try the Teletype Examples from the Load menu, in this order:
HELLO, WORLD! and stops.01000001 lights up.The keys a PC keyboard lacks, such as BREAK, RUBOUT and LINE FEED, are along the top of the paper.
The Altair's first piece of software was Microsoft's first product: Altair BASIC 3.2, written in 1975 by Bill Gates, Paul Allen and Monte Davidoff. It runs here, unmodified.
MEMORY SIZE?
TERMINAL WIDTH?
WANT SIN? Y
727 BYTES FREE
BASIC VERSION 3.2
[4K VERSION]
OK
PRINT 3.14 * 9
28.26
OK
727 bytes is all a 4 KB machine leaves you, which is exactly what the name means. Load it and look at the memory map in the Debugger before pressing RUN, and you can see BASIC filling fifteen of the sixteen pages. The Tutorial walks through it, including what loading it here skips: toggling in a 28-byte boot loader by hand, then waiting seven minutes for the paper tape.
The BASIC tape is in roms/, and roms/NOTICE explains what it is and why it is not under this repository's licence. Binary File… in the Load menu loads an image of your own instead.
Section 3 put a program in byte by byte, the way an owner did in 1975.
Intel's answer, the same year, was assembly language: you write
ADD B, and an assembler works out that it is 80. The Assembler
tab, under the panel, takes the language exactly as Intel's 8080
Assembly Language Programming Manual defines it, macros and all.
Here is section 3's program again, with names for its addresses instead of the numbers. It makes exactly the bytes you toggled in:
FIRST EQU 80H ; the first number
SECOND EQU FIRST+1 ; the second, the byte after it
SUM EQU FIRST+2 ; and where the sum goes
START: LDA FIRST ; A = the first number
MOV B,A ; keep it in B
LDA SECOND ; A = the second
ADD B ; A = A + B
STA SUM ; store the sum
JMP START ; and do it all again
What it takes is the whole of the manual's language: every
instruction, labels, EQU and SET, DB, DW and DS, expressions
and $, IF and ENDIF, and macros, whose labels are local to each
use as Intel specified. Its Examples menu has every example
program, from switches to lamps to macros (examples/).
Once a program is assembled, the line the program counter is on is
marked in green as you SINGLE STEP or STOP, and the line the caret is
on is banded across to its bytes. In the editor's corner, Copy
takes the source with you, and Clear starts afresh (Undo brings it
back). On a phone, the source and its bytes take turns, under the
Source and Bytes tabs. The design and its decisions are in
docs/assembler.md.
Serve the directory over HTTP and open it. With no web server installed, Python has one built in:
python3 -m http.server 8000
Then open http://localhost:8000/. To deploy, copy the whole directory to a web server; there is nothing to build, and no dependencies.
Opening index.html straight off the disk does not work, since
v1.7.0: the page's scripts are ES modules, and a browser runs no module
in a file:// page. Opened that way, the page shows only a notice that
says so and gives the command above.
Every file index.html names carries the version, css/style.css?v=1.7.0,
and so does every module the scripts import, through the page's import
map. A release asks for new names, so a cache can keep each file as long
as it likes and still never give an old one to the new page. Only
index.html itself must not be kept. On a server or a CDN that lets you
set the headers:
| What | Cache-Control |
|---|---|
index.html (and /) | no-cache: kept, but checked with the server each time, which costs a reply with no body when nothing changed |
Everything asked for with ?v= | public, max-age=31536000, immutable |
package.json, examples/, roms/ | no-cache; the page fetches these itself, and asks for a check anyway |
A CDN must count the query string in its cache key (most do unless told
not to), and should be told to purge index.html on each deploy.
GitHub Pages sets no headers you can change and keeps everything for 10
minutes, so there a release reaches everyone within 10 minutes.
The version is kept in one place, package.json; the names in
index.html are copies, written from it and never by hand. Set it with
npm, which writes them too:
npm version 1.7.0 # or: npm version patch | minor | major
It sets the version, then runs npm run stamp
(tools/stamp.mjs) to write it into index.html's
file names and import map, and stops there: it does not commit or tag
(.npmrc), since a release is tagged on GitHub, on its merge
commit. Commit the two files as usual. A version changed any other way,
by hand in package.json, needs npm run stamp after it; until then
npm test fails and says so, so a release cannot go out half stamped.
The logo is in images/ in three forms: the machine alone, 16:9
(8800-simulator-logo.svg), and the machine with its name, 8:1, in
white for dark backgrounds and black for light ones
(8800-simulator-logo-text-white.svg, -text-black.svg). The toolbar
shows the one with the name, and on a phone the machine alone; this
README shows the name in whichever colour suits the reader's theme.
The favicons and home screen icons are drawn from the 16:9 one, and
kept with it in images/: favicon.svg, favicon.ico (16, 32 and 48
pixels), and the 180, 192 and 512 pixel PNGs that index.html and
manifest.webmanifest name. After a change to
the logo, draw them again (it needs Chrome, as the browser checks do):
npm run icons
npm test fails until they have been, since it checks that the SVG
favicon still has the logo's drawing.
| File | What it is |
|---|---|
| index.html, css/style.css | The page: toolbar, panel, dock, dialogs |
| js/main.js, js/app.js | The page's one script, and the app it starts; every file is an ES module |
| js/8080.js | The Intel 8080 CPU core, maly/8080js |
| js/sim8800.js | The machine: memory, the front panel's logic, the ports |
| js/sio.js, js/teletype.js | The serial boards, and the Teletype's paper |
| js/panel.js | The page's own logic, at its core: the status line, About, and building the page |
| js/panel-front.js | The front panel: its switches, lamps and sounds, and the big switches under it |
| js/panel-load.js | Putting a program in: Load, the examples, 4K BASIC, files, the Memory menu |
The design notes say why things are the way they are: docs/ui-design.md for the layout and its principles, docs/ms-basic-4k.md for the memory, the serial boards, the Teletype and BASIC, docs/assembler.md for the assembler and the language it takes, and docs/kill-the-bit.md for the address-bus trick Kill the Bit relies on.
npm test
Node.js 24, nothing to install. The suite covers the 8080 CPU, the front panel, the serial boards and the Teletype, the page's own logic and translations, the link format, the assembler against Intel's manual, every program in examples/, and 4K BASIC booting and running end to end. It runs on each push and pull request.
The page itself - clicks, menus, the Assembler's editor, the layout - is checked in a headless Chrome:
npm run test:browser
npm run test:browser -- sync clear
It takes a minute or so and needs Chrome installed (or CHROME set to
its path, Chromium too), so it is not part of CI: run it by hand
before a release. The checks are in tests/browser/.
The JSDoc types are checked against the code by TypeScript's checker,
which npx fetches for the run; nothing is compiled, and the page
runs the files as they are. CI runs it after the tests:
npm run typecheck
Only the files that start with // @ts-check are checked, so far
js/asm8080.js and js/sim8800.js; tsconfig.json
says how strictly.
A link opens the simulator with a program loaded at 0000H, ready to
RUN. The fields go after ? or #:
https://wixette.github.io/8800-simulator/?hex=3E8CD3FF76
Try it:
the bytes are MVI A,8CH, OUT 0FFH and HLT. Click RUN and the
data lamps show 10001100.
The bytes of hex can run together, or be separated by + or %20.
Memory is installed to fit, and zeros at the end do not count.
Share writes its links after #, which is never sent to the web
server, so a long one is not turned away (GitHub Pages refuses a link
of 16,000 characters). It leaves out whatever a machine just switched
on would have anyway. Memory in use that fits in 256 bytes is written
as hex, so it can be read in the link; past that it is compressed under
zip, and 4K BASIC comes to about 4,500 characters instead of 8,300.
Every field is optional:
| Field | Holds |
|---|---|
hex | Memory from 0000H up, in hex |
zip | The same memory, deflated and in URL-safe base64, in place of hex |
mem | Installed memory: 256, 4096 or 8192 (decimal) |
pc, sp | The 16-bit registers, in hex |
a, b, c, d, e, h, l, f | The 8-bit registers, in hex, f being the flags |
sw | The address switches, A15–A0, as a 16-bit hex word |
A linked machine always opens stopped. The Teletype's paper and the interrupt enable are not in the link. The format is a promise to everyone who has put a link in a document: fields may be added, but never renamed or read differently (js/link.js).
The Intel 8080 CPU core is maly/8080js.
The Quick Tutorial in the simulator uses an example program from the original Altair 8800 Operator's Manual.
The interaction design took another Altair 8800 simulator as a reference.
| js/panel-debug.js | The Debugger: the memory dump and its editing, the next instruction, the memory map |
| js/panel-link.js, js/panel-tty.js, js/panel-dock.js | Program links and Share; the Teletype; the dock and its tabs |
| js/link.js | The program link format |
| js/asm8080.js, js/asmtab.js | The 8080 assembler, and its tab |
| js/dropdown.js, js/dialog.js | The menus and the dialogs |
| js/l10n.js | Every message, in ten languages |
| tools/stamp.mjs, tools/icons.mjs | Not part of the page: the version stamp, and drawing the icons from the logo |