Feb 162021



– EEC –
Early Electronic Calculator
Technology Reference

A source of information about the technology used in the construction of early electronic calculators.

Technical data for electronic calculators manufactured from the 1960s to the early 1970s is difficult to come by. Most of these machines utilized proprietary and now obsolete integrated circuits. For SSI-based calculators technical data is useful and often a necessity if one wishes to repair such units.

This site presents some technical data about these machines for those who may have an interest or need for it. The site is organized broadly into:

  • data about specific models of calculators (schematic, etc.)
  • data about integrated circuits (pinouts, logic levels, etc.)
  • simulations of specific models of calculators

Most of this data has been derived from the reverse engineering of various calculators. An example of this process is presented in the tale of fixing the Facit 1123.

The initial motivation for deriving and collecting this data was to assist in the repair of the units. However it has turned into an interesting study in the variety of technology, architecture and algorithms used. SSI-based calculators from the late 1960s were some of the first products marketed outside the military and large-institutional markets to utilise digital integrated circuits. The “bit-at-a-time serial-data” architecture of most of these units harkened back to the architecture of some of the first computers such as the SSEM.

Photo Galleries

Desk Calculators Pocket Calculators


 Posted by at 7:34 am
Jan 162021


This post is about the magic constant 0x5f3759df and an extremely neat hack, fast inverse square root, which is where the constant comes from.

Meet the inverse square root hack:

float FastInvSqrt(float x) {
  float xhalf = 0.5f * x;
  int i = *(int*)&x;         // evil floating point bit level hacking
  i = 0x5f3759df - (i >> 1);  // what the fuck?
  x = *(float*)&i;
  x = x*(1.5f-(xhalf*x*x));
  return x;

What this code does is calculate, quickly, a good approximation for


It’s a fairly well-known function these days and first became so when it appeared in the source of Quake III Arena in 2005. It was originally attributed to John Carmack but turned out to have a long history before Quake going back through SGI and 3dfx to Ardent Computer in the mid 80s to the original author Greg Walsh. The concrete code above is an adapted version of the Quake code (that’s where the comments are from).

 Posted by at 6:16 pm
Jan 012021

Pandova bastlírna

Původním zaměřením jsem elektrikář-slaboproudař, a tak mě občas chytne (kromě softwerařiny) zabývat se vývojem elektroniky, a to především mikročipy. Výsledky nejsou profi, ale třeba budu někoho inspirovat v jeho tvorbě. Především se snažím zaměřovat stylem “za málo peněz hodně muziky” = vytáhnout maximum z jednoduchého zařízení. Zaměřuji se především na procesory ATmega8.


ATpad – Herní konzole s procesorem ATmega8. Výstup na televizor (PAL, NTSC) nebo VGA monitor. Spouštění programů z SD karty. Port s 2 digitálními vstupy/výstupy a 2 analogovými vstupy (možné připojení analogové joysticku).

ET-57 – Klon kalkulátoru TI-57 s procesorem ATmega8.

ET-58 – Klon kalkulátoru TI-58 s procesorem ATmega328.
TI58T tiny – Replika kalkulátoru TI-58C s procesorem ATmega8. Přesnost výpočtů na 19 platných číslic, exponent 4 číslice. NEDOKONČENO
TI59R revival – Upgrade kalkulátoru TI-59 s procesorem ATmega644P. Přesnost výpočtů na 19 platných číslic, exponent 4 číslice. NEODLADĚNO

Měřicí přístroje

RBox – Referenční odporová dekáda 0.1%.

FreqGen – Frekvenční generátor funkcí s procesorem ATmega8 (1 Hz až 8 MHz).

FreqMeter – Přesný měřič frekvence s procesorem ATmega8 (1 Hz až 50 MHz, příp. 1 Hz až 100 MHz).

RCLmeter – Měřič odporů, kondenzátorů, cívek, ESR, napětí a indikátor zkratů, s automatickou změnou rozsahů.


Craft – Minimalistické VGA demo s procesorem ATmega88 od švédského autora Linus Akesson.


Další (starší) projekty:




domovská www:

 Posted by at 3:35 pm
Dec 072020


HP Calculator Literature

Filter by:    

Title Edition Published Author Source Models Languages Format Pages File Size
WP 34S Beginners Guide n/a July 2012 Ciaran J. Brady Books WP 34S English Original Document 187 3.06 MB
WP 34S Owner’s Manual 2.2 November 2011 Walter Bonin Community WP 34S English Original Document 103 3.88 MB
WP 34S Owner’s Manual 3.0 March 2012 Walter Bonin Community WP 34S English Original Document 118 4.84 MB
WP 34S Owner’s Manual 3.1 November 2012 Walter Bonin Community WP 34S English Original Document 211 8.28 MB

4 books shown

Part of the HP Calculator Archive,
Copyright 1997-2020 Eric Rechlin.
Manuals copyright Hewlett-Packard or their respective authors. Redistributed with permission.

 Posted by at 6:46 pm
Nov 142020

HP Pioneer series calculator internals
Takayuki HOSODA
Nov. 17. 2009

 Japanese edition is here.

PCB of the HP pioneer series calculators

Left: HP-17BII, Center: HP-27S, Right: HP-42S(modified)

Membrane switches


Key pad and back plate (with LCD)

Partial schematic of the HP 17BII/27S/42S


HP 42S memory upgrade and overclock
Pioneer “Observational Internals”, Paul J. Brogger [Mail]  Copyright (c) HOSODA Takayuki. All rights reserved.
Powered by

 Posted by at 11:46 am
Oct 312020

commanderx16 commanderx16emul
  • The evolution of 8-Bit

    * Inexpensive, reliable, educational
    * Unique, not a clone or a sequel
    * A real CPU not emulation
    * Classic chips on-board

The modern retro computer


Your wish is my command.


  • Commander X16 is coming…

    See FAQ & forum for announcements!
    Download the emulator to get READY.
    Pictured: Commander X16P concept art

 Posted by at 9:12 am
Oct 242020



Physical Interface

From a pinout perspective, UART signals only require one line for unidirectional communications, although two are typically used for bi-directional transmit and receive. Being asynchronous, UART signals don’t require any other clock line because the two UART devices agree on a common baud rate, stop, start and data bits. This makes the receiver capable of decoding the data. UART is connected by crossing the TX and RX lines, as shown below:

Connecting UART between two devices such as an MSP430 and another generic productUART transmits bits sequentially by pulling the UART line low for a fixed amount of time determined by the baud rate. The UART line when idle is high at the I/O level, 3.3V or whatever the VCC of the MSP430 is set. RS232, on the other hand, uses similar signaling to UART but also incompatible voltage levels (the voltages are high and some are negative) that will damage the MSP430. Therefore, never connect an RS232 device directly to the MSP430. Use a MAX232 or similar device to convert between the two signal levels.

The smallest element of transmission is the UART frame or character, which consists of the Start bit/s, data bits, stop bits and optional parity bits, as shown below:

Bit number 1 2 3 4 5 6 7 8 9 10 11
Start bit Start bit Data Bit Data Bit Data Bit Data Bit Data Bit Data Bit Data Bit Data Bit Stop Bit Stop Bit

The start bits alerts the receiver that data is coming. Without it, if the first bit was a ‘1’, it would be seen as an idle line since an idle UART line is also high. The number of data bits is typically 8, but it can be configured for 7 bits as well. Although some UART receivers can use a different number of bits, only 8 or 8 bits are supported by the MSP430. After the data bits stop bits are sent along with an optional parity bit.

MSP430 families contain different peripherals capable of UART communications. Among these are USCI, USART and eUSCI modules. UART can also be generated using timers or even bit-banged. Some peripherals have sophisticated options that we will not cover since they are rarely used.

Configuring the MSP430 for UART operation

We previously covered the issue of signal multiplexing. In order to use UART, specific pins that are connected to the UART module must be used, and the pin muxing must choose the Primary Peripheral mode. On the MSP430G2553 that is on the MSP430 Launchpad, UCA0 pins are present on pins P1.1 and P1.2 as UCA0RXD and UCA0TXD, respectively. Setting the pin muxing is simple since TI provides the information for the bit settings in the datasheet of the device. In this case, UART requires both PxSEL and PxSEL2 to be set to ‘1’. PxDIR does not need to be configured.

Configuring MSP430 Pin Muxing for UART

P1SEL |= (BIT1 | BIT2);
P1SEL2 |= (BIT1 | BIT2);

With the pins configured, we must configure the clocks for UART. The baudrate generation requires a clock of a certain precision. Although baudrates vary, 9600 and 115200 baud are the most common and we will focus on them. In order to generate a baud rate, we must feed a large enough clock so that it can be divided by the baud rate generator for the actual baud rate. For 9600 baud we can use both the slow 32.768kHz crystal if one is present, or a faster source such as the internal DCO or an external crystal. 115200 baud requires a fast clock, so only the DCO and a fast external clock can be used. Below we have the code needed to configure USCI_A0 for UART operation at 9600 baud:

Configuring MSP430 Pin Muxing for UART

#include <msp430.h>

int main(void)

/* Use Calibration values for 1MHz Clock DCO*/

/* Configure Pin Muxing P1.1 RXD and P1.2 TXD */
P1SEL = BIT1 | BIT2 ;
P1SEL2 = BIT1 | BIT2;

/* Place UCA0 in Reset to be configured */

/* Configure */
UCA0BR0 = 104; // 1MHz 9600
UCA0BR1 = 0; // 1MHz 9600
UCA0MCTL = UCBRS0; // Modulation UCBRSx = 1

/* Take UCA0 out of reset */

/* Enable USCI_A0 RX interrupt */

__bis_SR_register(LPM0_bits + GIE); // Enter LPM0, interrupts enabled

/* Echo back RXed character, confirm TX buffer is ready first */
#pragma vector=USCIAB0RX_VECTOR
__interrupt void USCI0RX_ISR(void)
while (!(IFG2&UCA0TXIFG)); // USCI_A0 TX buffer ready?
UCA0TXBUF = UCA0RXBUF; // TX -&gt; RXed character

The clock source for the UART baud generator is SMCLK sourcing the DCO running at 1MHz. Before we can configure the UART peripheral we need to place it in reset mode. Not all registers require this but it is best to do so when first configuring USCI, whether it’s for UART or any other mode. Notice that we use the assignment operator, so all the other bits are set to zero. With the reset in place, we make SMCLK the clock source for the UART. Being flexible, there are other possible options for the UCSSELx:

  • 00b = UCAxCLK (external USCI clock)
  • 01b = ACLK
  • 10b = SMCLK
  • 11b = SMCLK

UART can actually use a cloc

 Posted by at 6:45 am
Oct 242020

UART Serial communication with MSP430 microcontroller


Table of Contents


To use UART communication module of MSP430 microcontroller, first you should understand what is UART communication? What is Serial communication? MSP430G2 launch Pad has on board MSP430G2553 microcontroller. MSP430G2553 microcontroller has one built in circuit for UART. So MSP430G2 launchpad has only on UART communication module which can be used to send and receive data serially.  This board also supports I2C and SPI communication protocols. SPI and I2C are also serial communication protocols.  UART communication is not a communication protocol but a physical dedicated circuit in the form of integrated circuit or embedded inside a microcontroller. On the other hand, both SPI and I2C are communication protocols. you may like to check getting started tutorials on MSP430:

What is UART communication ?

  • UART stand for Universal Asynchronous Receiver and Transmitter. UART can transfer data bit by bit serially.
  • There are other parallel communication protocols exists which are used to transfer data in parallel mode like 8 bit at time.   It can transfer only one bit at a time.
  • By parallel communication data can be transferred with high speed. But speed come with cost,  it required as many wires as many bits user want to transfer at a time.
  • Serial communication consists of only two wires, transmission wire and receive wire.
  • Receiver wire is used to receive data sequentially from other UART device.
  • Transmitter wire is used to send data sequentially to other UART microcontroller or device.
  • UART communication pins of MSP430G2 launchPad are shown in figure.UART communication MSP430 microcontroller
  • Pin number three is transmission pin and pin number 4 is a receiver pin.
 Posted by at 6:42 am
Oct 182020


Welcome to the vDosPlus home page!

vDosPlus website URL:

vDosPlus (formerly vDos-lfn) is a free general-purpose non-gaming DOS emulator running on Windows, based on vDos and DOSBox. vDosPlus is designed to run non-gaming DOS applications in all current Windows versions. NTVDM (NT Virtual DOS Machine) is included in 32-bit Windows, but NOT in 64-bit Windows. However, most today’s Windows is now 64-bit, and to run DOS programs you need a DOS emulator. vDosPlus is exactly for this purpose, and like original vDos it provides advanced features such as support for file-locking (needed by multi-user applications) and printing to Windows-only (GDI) printers, but it also has many unique features such as a tighter integration with Windows and enhanced keyboard, mouse and display support. It was formerly known as vDos-lfn because its initial focus was added support for Windows-style long filenames or LFNs in addition to traditional DOS 8.3 file names, but now with a wide range of additional features there are much more than this. It is based on mature projects and also well tested by for example the XyWrite community and many normal or power users of various DOS applications, so it should be considered pretty stable as well.

Highlights of vDosPlus’s Features:

– It runs in both 32-bit and 64-bit Windows, including Windows XP, Vista, 7, 8, 8.1 and 10 (all versions up to the latest release; Windows 2000 can be supported too)
– Run your DOS applications reliably in a DOS virtual machine; the text-mode DOS screen (either in a window or full-screen) is fully scalable with a TTF font
– Network support and multi-user environment friendly with file- and record locking; you can always run multiple DOS applications in different vDosPlus sessions
– Tight integration with Windows, including direct support for Windows-style long filenames (LFN), copying to and pasting from the Windows clipboard, and so on
– Support for multi-monitor setups, on-screen text styles (such as bold and italics), border/edge padding, mouse wheel scrolling, transparent window, and many more
– Built-in 4DOS 8.00 shell which provides powerful command-line and other functionalities; you can also find many useful information from its interactive help system
– You can customize the config settings easily by editing the configuration file, changing them on the fly, or you can simply use the default settings for vDosPlus
– Powerful printing functionalities to print to PCL and PostScript printers as well as Windows-only (GDI) printers directly; printing to PDF is also supported

Screenshots of vDosPlus

Below are some screenshots of software running in vDosPlus.

4DOS Help in vDosPlus
WordPerfect 6 in vDosPlus
XyWrite 4 in vDosPlus
4DOS Help running in vDosPlus
WordPerfect 6 running in vDosPlus
XyWrite 4 running in vDosPlus


 Posted by at 5:29 pm
Oct 182020



Cross-platform DOS emulation package
Complete, accurate emulation and more

What is DOSBox-X?

DOSBox-X is an open-source DOS emulator for running DOS games and applications.
DOS-based Windows such as Windows 3.x and Windows 9x are officially supported.
Compared to DOSBox, DOSBox-X is much more flexible and provides more features.
Look at the DOSBox-X Wiki for more information about DOSBox-X and usage guides.

 Posted by at 5:24 pm
Sep 282020




Welcome the Anita Calculator simulator site. In the pages of this site you will find a collection of simulators for various calculators associated with the Sumlock Anita company that shone brightly, but all too briefly, in the sixties and early seventies. All the simulators have an association with this company; either they were made at the U.K. factory in Portsmouth, are variants of calculators that were, or were made by companies that were associated with Sumlock Anita during it’s existence. The simulators are meant

to give a flavour of what these devices were like during that ‘golden age’ of calculator development. All the images of calculators here (except one of a comptometer) give access to a simulator so that you can try them out for yourselves (simply click on the image). Where possible a manual is provided on this site, or a link to where one may be found is given, if this is available.

Not all the simulators are represented in my collection, but more details of those calculators that are can be found on their individual pages accessible via the galleries page. These pages have working simulators on them as well. All of the simulators can be downloaded for running offline. The ZIP download packages can be found on the downloads page. For general comments and feedback (it’s always nice to hear from people), please drop me an e-mail

You can jump directly to the relevant simulator pages using the links below, or use the navigation bar on the left to view all my other pages, including pictures of the items in my collection of Sumlock Anita calculators. If you would like just to browse, follow the ‘next’ / ‘prev’ sequential links at the bottom of each page. If you don’t see any navigation bar please click here.

Simulator Page Contents

Sumlock Anita Calculators
Rockwell Calculators
Associated Company Calculators

Next Page->

Page last updated 1st January 2020.

© 2003-2020 Simon Southwell. All rights reserved.


 Posted by at 7:27 pm
Jun 202020


Generating a sine wave

In Hardware on May 18, 2012 at 00:01

After the recent pretty disappointing results with a transformer-based Component Tester, I’d like to try and generate a ± 10 V sine wave at approximately 50 Hz in some other way. Using as few components as possible.

 Posted by at 7:25 pm
Jun 202020


Arduino based digital clock.

Student-Hobbyist Electronics Projects Tutorials

by Lewis Loflin


View all of my You Tube Videos
Also visit and subscribe to My YouTube Channel


Introduction – The purpose of these pages is to introduce the student and hobbyist to electronics projects. My hope is generate interest for those thinking about entering a high tech field, or simply to have fun.

I’ve been a part-time adjunct professor at a local community college teaching electricity and electronics. My electronics website reflects what I’ve taught or been asked to look into by visitors. I have 40 years experience in electronics from vacuum tubes to modern solid state and industrial controls. In college I had a year each of physics, chemistry, and biology along with C, C++. Pascal, and assembly.

 Posted by at 6:37 pm
Jun 202020


Detailed Features about:

  1. Oscilloscope (dual channel, xy, time division, trigger);

  2. Spectrum Analyzer with amplitude and phase display (linear, log, lines, bar, octaves band analysis 1/3, 1/6, 1/9, 1/12, 1/24);

  3. Wave-form generator with “custom functions”, triangular, square, sinus, white noise and pulse generation (NO ALIASING);

  4. Frequency meter (in time and frequency domain) and counter; in time domain by means of a real time zero crossing algorithm;

  5. Volt meter with DC, true RMS, peak to peak and mean display; 

  6. Filtering (low pass, hi pass, band pass, band reject, notch, “diode”, DC removal);

  7. Memo windows (data log) for analysis and storage of time series, spectrum and phase  with “triggering” events; possibility to save in various formats and display them with a viewer;

  8. A TRUE software digital analog conversion (for complete signal reconstruction using Nyquist theorem) ;

  9. Frequency compensation: one can create/edit a custom frequency response and  add it to the spectrum analyzer spectrum ; added standard weighting curves A,B,C in parallel with custom frequency response;

  10. Support for 8/16/24 bit soundcard by means of API calls;

  11. Unlimited frequency sampling (depend from the capabilities of your soundcard);

  12. Cepstrum analysis;

  13. Cross Correlation;

  14. Extended THD measurements, with automatic sweep and compensation.

  15. ZRLC-meter with Vector scope, automatic sweep in time and frequency for automatic measurement.

VA main form (version 8.x.x)

[Product Image]

(1) – Oscilloscope

Click to enlarge in a new window

  1. Dual channel

  2. Bandwith : depends from your soundcard (typical  20 Khz) up to 96 Khz (192 Khz sampling frequency)

  3. Resolution from 8 bit (S/N 46 dB) up to 24 bit (S/N >120 dB)

  4. Time division adjust according the sampling frequency and sample resolution

  5. Trigger (positive/negative slope) independent for both channels

  6. Complete software D/A of digital samples : the Nyquist theorem allows reconstructing exactly the input signal

  7. Utilities for quick frequency determination (hold left mouse button down and move mouse to get frequency/amplitude)

  8. Y-axis in Volt and percent full scale

  9. Auto calibration of scope (and spectrum) in volts (need an input signal of known amplitude)

(2) – Spectrum Analyzer

Click to enlarge in a new window

  1. Dual channel

  2. Bandwidth : same as point (1) (oscilloscope function): is the half of the sampling frequency. Typical for 44100 Hz is 22050 Hz (up to 96 Khz or ore depending of the acquisition board)

  3. Resolution from 8 bit (S/N 46 dB) up to 24 bit (S/N >120 dB)

  4. X-axis in Hz, logarithmic and linear; zoom x1..x16

  5. Y-axis in dB or Volt (calibration needed); linear/logarithmic; zoom

  6. Average on spectrum up to 200 buffer

  7. Direct window for amplitude  with mouse

  8. Auto-scale

  9. Capacity to modify the zero dB level  (manually/automatically)

  10. Octave band analysis (1/1, 1/3, 1/6, 1/9, 1/12, 1/24)

(3) – Wave-form generator

Click to enlarge in a new windowClick to enlarge in a new window

  • Dual channel

  • Independent sampling frequency/resolution from scope/spectrum (up to 192 Khz/24 bit)

  • Phase between channels (degree)

  • Direct real time generation/ loop with predefined buffer

  • Waveform CUSTOM, built with harmonics (with save/load in file “.fun” of defined waveform)

  • Modulation of custom waveform with sinus/square/triangular

  • Predefined waveform : sinus, square, triangular (parametric), white noise, pink noise, pulse, sinusoidal sweep 

  • Local volume levels

  • Real time parameters variation (amplitude, frequency, phase between channels, type of waveform)

(4) – Frequency meter

Click to enlarge in a new window

  • Dual channel

  • Frequency meter in Hz/Time/Counter of the input signal being visualized in spectrum/scope

  • Read the frequency of the harmonic of maximum amplitude

  • Counter with threshold level

(5) – Volt meter (calibration needed)

Click to enlarge in a new window

  • Dual channel

  • Vpp, True Rms

  • Hold function

(6) – Filtering

Click to enlarge in a new window

  • FIR low pass cut-off frequency user defined

  • FIR high pass cut-off frequency user defined

  • FIR band pass cut-off frequencies user defined

  • FIR band reject cut-off frequencies user defined

  • IIR notch cut-off frequency user defined

  • IIR notch-inverted cut-off frequency user defined

  • “Diode” function

  • DC removal

  • Dual filter (one for each channel)

(7) – Memo windows

Click to enlarge in a new windowClick to enlarge in a new window

  • Aquiring of spectrum with average

  • Edit offline (while VA running) of aquired spectrum: zoom, navigate

  • Saving of spectrum in TXT format

  • Clipboard for aquired spectrum

  • Print of aquired spectrum

  • Mark points for each valid point (harmonic) of spectrum

  • Aquiring of scope points (points aquired in time domain)

  • Edit offline (while VA running) of aquired time series: zoom, navigate

  • Saving of samples in TXT format

  • Clipboard for aquired samples

  • Print of aquired samples

  • D/A conversion: the points aquired may be converted using Nyquist theorem for full reconstruction of  signal in time domain (see point 8 for D/A in real time)

(8) – real time DIGITAL/ANALOG conversion

  • D/A in real time

  • Dual channel

  • Allows visualizing each aquired harmonic

Points (8) need a clairification:

VA has the unbeatable feature  to perform a full real time Digital-Analog conversion for the oscilloscope function.

Consider using a frequency sampling of (standard) 44100 Hz, with a 16 bit resolution (resolution is not relevant for the purpose of the discussion below…)

Other programs similar to VA simply plot the raw points on the screen, which means you can’t easily analyze signals with a frequency higher than 3000/5000 Hz (there are limited points to plot). Even worse, think a sinusoidal signal of 20 KHz. You would have only 2 points (more or less) per cycle! … The Nyquist theorem says that it is sufficient to RECONSTRUCT the original  signal…try to see what happens if you draw a sine with only two points …it will appear like a triangular waveform…

Try the power of VA enabling the function “full D/A”, apply a sinusoidal signal of 15-20 KHz (for example using the Waveform generator included in VA) finally use the “Time division” control for the selected channel (mS/d) to display the signal at the desired detail level. You will see a perfect waveform with all the points of the original signal (not only two).

(9) Frequency compensation

Visual Analyser allows you to apply a predefined frequency response to compensate (for instance) the frequency response  of a microphone. You should know the frequency response of your microphone; normally professional microphone should be shipped with the typical frequency response. You can add a limited number of points in VA, and apply. VA will interpolate a continues curve by means of cubic spline interpolation algorithm. You can do it through the windows below.

 Posted by at 1:14 pm
Apr 272020


“n FOR-NEXT runs n+1 loops by design”

Why and how to cope with:

eForth FOR .. NEXT

Thomas edited this page on Dec 26, 2018 · 1 revision

Discussion of eForth FOR .. NEXT

While it’s advisable to use the STM8 eForth DO .. LEAVE .. LOOP/+LOOP structure instead of FOR .. NEXT and its variants, the following discussion deals with the most main properties, idioms and limitations of the this “eForth-ism”.

Basic properties of eForth FOR .. NEXT

Among “small Forth implemenations” the eForth FOR .. NEXT construct is idiosyncratic, and some of its properties and idioms are rather difficult to understand.

Here is a the basic FOR .. NEXT loop:

: test-for
   FOR I . NEXT ;

NEXT decrements the loop counter on the return stack (accessible with I or R@) and loops while the counter is positive. 4 test-for prints 4 3 2 1 00 test-for prints 0, and -1 test-for prints -1.

The following FOR .. NEXT properties are noteworthy:

  • at least one iteration, with the loop counter equal to the input to FOR will be performed
  • the nuber of iterations is limited to 32768, and
  • the loop count will be “one-too-many” compared to standard loop structures (e.g. DO .. LOOP)

eForth FOR .. AFT .. THEN .. NEXT

The most unusual feature eForth provides is the word AFT:

: test-aft1 ( n -- )
      \ first loop
      ."  for"
         \ following iterations
         ."  aft"
      \ all iterations
      I .
   NEXT ;

2 test-aft1 prints for 2 aft 1 aft 0. Why one would need such a control structure is all but obvious. The eForth core implementation use of AFT, however, shows that it not only works around the “one-too-many” iterations in FOR .. NEXT, but it also provides loop count testing if the actual “loop clause code” is in the AFT .. THEN block:

: test-aft2 ( n -- )
       I .

Running 3 test-aft2 prints 2 1 0, and 0 test-aft2 or -1 test-aft2 print nothing at all. This structure is widely used in the eForth core, e.g. in CMOVESAME? and TYPE. The effect is that input testing around FOR .. NEXT, especially for 0 counts, isn’t needed.

eForth FOR .. WHILE .. NEXT .. ELSE .. THEN

A loop structure similar to DO .. LEAVE .. LOOP can be implemented in “pure eForth” with an idiomatic combination of FOR .. NEXTWHILE, and ELSE .. THEN:

: test-for-while ( n1 n2 -- )
      I . \ limit not reached
      ."  end"
      ."  limit"
      R> DROP \ remove the FOR loop counter
   DROP ;   \ drop limit

In this example, 5 10 test-for-while prints 10 9 8 5 6 limit, and 5 4 test-for-while prints 4 3 2 1 0 end.

WHILE puts a the address of its conditional branch target on the stack above the start address of FOR the for loop (which is used when compiling NEXT). During compilation, ELSE then uses this address to make WHILE exit to the code block delimited by THEN. Note that the ELSE clause is responsible of removing the loop counter from the return stack.

Note that the FOR .. WHILE .. NEXT .. ELSE .. THEN idiom can’t be mixed with the FOR .. AFT .. THEN .. NEXT idiom!

 Posted by at 7:22 am
Apr 052020


Easy Forth

by Nick Morgan

View on GitHub


This small ebook is here to teach you a programming language called Forth. Forth is a language unlike most others. It’s not functional or object oriented, it doesn’t have type-checking, and it basically has zero syntax. It was written in the 70s, but is still used today for certain applications.

Why would you want to learn such an odd language? Every new programming language you learn helps you think about problems in new ways. Forth is very easy to learn, but it requires you to think in a different way than you’re used to. That makes it a perfect language to broaden your coding horizons.

This book includes a simple implementation of Forth I wrote in JavaScript. It’s by no means perfect, and is missing a lot of the functionality you’d expect in a real Forth system. It’s just here to give you an easy way to try out the examples. (If you’re a Forth expert, please contribute here and make it better!)

I’m going to assume that you know at least one other programming language, and have a basic idea of how stacks work as a data structure.

Adding Some Numbers

The thing that separates Forth from most other languages is its use of the stack. In Forth, everything revolves around the stack. Any time you type a number, it gets pushed onto the stack. If you want to add two numbers together, typing + takes the top two numbers off the stack, adds them, and puts the result back on the stack.

Let’s take a look at an example. Type (don’t copy-paste) the following into the interpreter, typing Enter after each line.

<- Top

Every time you type a line followed by the Enter key, the Forth interpreter executes that line, and appends the string ok to let you know there were no errors. You should also notice that as you execute each line, the area at the top fills up with numbers. That area is our visualization of the stack. It should look like this:

1 2 3 <- Top

Now, into the same interpreter, type a single + followed by the Enter key. The top two elements on the stack, 2 and 3, have been replaced by 5.

1 5 <- Top

At this point, your editor window should look like this:

1 ok 2 ok 3 ok + ok

Type + again and press Enter, and the top two elements will be replaced by 6. If you type + one more time, Forth will try to pop the top two elements off the stack, even though there’s only one element on the stack! This results in a Stack underflow error:

1 ok 2 ok 3 ok + ok + ok + Stack underflow

Forth doesn’t force you to type every token as a separate line. Type the following into the next editor, followed by the Enter key:

123 456 +
<- Top

The stack should now look like this:

579 <- Top

This style, where the operator appears after the operands, is known as Reverse-Polish notation. Let’s try something a bit more complicated, and calculate 10 * (5 + 2). Type the following into the interpreter:

5 2 + 10 *
<- Top

One of the nice things about Forth is that the order of operations is completely based on their order in the program. For example, when executing 5 2 + 10 *, the interpreter pushes 5 to the stack, then 2, then adds them and pushes the resulting 7, then pushes 10 to the stack, then multiplies 7 and 10. Because of this, there’s no need for parentheses to group operators with lower precedence.

Stack Effects

Most Forth words affect the stack in some way. Some take values off the stack, some leave new values on the stack, and some do a mixture of both. These “stack effects” are commonly represented using comments of the form ( before -- after ). For example, + is ( n1 n2 -- sum ) – n1 and n2 are the top two numbers on the stack, and sum is the value left on the stack.

Defining Words

The syntax of Forth is extremely straightforward. Forth code is interpreted as a series of space-delimited words. Almost all non-whitespace characters are valid in words. When the Forth interpreter reads a word, it checks to see if a definition exists in an internal structure known as the Dictionary. If it is found, that definition is executed. Otherwise, the word is assumed to be a number, and it is pushed onto the stack. If the word cannot be converted to a number, an error occurs.

You can try that out yourself below. Type foo (an unrecognized word) and press enter.

<- Top

You should see something like this:

foo foo ?

foo ? means that Forth was unable to find a definition for foo, and it wasn’t a valid number.

We can create our own definition of foo using two special words called : (colon) and ; (semicolon). : is our way of telling Forth we want to create a definition. The first word after the : becomes the definition name, and the rest of the words (until the ;) make up the body of the definition. It’s conventional to include two spaces between the name and the body of the definition. Try entering the following:

: foo  100 + ;
1000 foo
foo foo foo

Warning: A common mistake is to miss out the space before the ; word. Because Forth words are space delimited and can contain most characters, +; is a perfectly valid word and is not parsed as two separate words.

<- Top

As you’ve hopefully figured out, our foo word simply adds 100 to the value on top of the stack. It’s not very interesting, but it should give you an idea of how simple definitions work.

Stack Manipulation

Now we can start taking a look at some of Forth’s predefined words. First, let’s look at some words for manipulating the elements at the top of the stack.

dup ( n -- n n )

dup is short for “duplicate” – it duplicates the top element of the stack. For example, try this out:

1 2 3 dup
<- Top

You should end up with the following stack:

1 2 3 3 <- Top

drop ( n -- )

drop simply drops the top element of the stack. Running:

1 2 3 drop

gives you a stack of:

1 2 <- Top
<- Top

swap ( n1 n2 -- n2 n1 )

swap, as you may have guessed, swaps the top two elements of the stack. For example:

1 2 3 4 swap

will give you:

1 2 4 3 <- Top
<- Top

over ( n1 n2 -- n1 n2 n1 )

over is a bit less obvious: it takes the second element from the top of the stack and duplicates it to the top of the stack. Running this:

1 2 3 over

will result in this:

1 2 3 2 <- Top
<- Top

rot ( n1 n2 n3 -- n2 n3 n1 )

Finally, rot “rotates” the top three elements of the stack. The third element from the top of the stack gets moved to the top of the stack, pushing the other two elements down.

1 2 3 rot

gives you:

2 3 1 <- Top
<- Top

Generating Output

Next, let’s look at some words for outputting text to the console.

. ( n -- ) (period)

The simplest output word in Forth is .. You can use . to output the top of the stack in the output of the current line. For example, try running this (make sure to include all the spaces!):

1 . 2 . 3 . 4 5 6 . . .
<- Top

You should see this:

1 . 2 . 3 . 4 5 6 . . . 1 2 3 6 5 4 ok

Going through this in order, we push 1, then pop it off and output it. Then we do the same with 2 and 3. Next we push 45, and 6 onto the stack. We then pop them off and output them one-by-one. That’s why the last three numbers in the output are reversed: the stack is last in, first out.

emit ( c -- )

emit can be used to output numbers as ascii characters. Just like . outputs the number at the top of the stack, emit outputs that number as an ascii character. For example:

 33 119 111 87 emit emit emit emit
<- Top

I won’t give the output here so as to not ruin the surprise. This could also be written as:

87 emit 111 emit 119 emit 33 emit

Unlike .emit doesn’t output any space after each character, enabling you to build up arbitrary strings of output.

cr ( -- )

cr is short for carriage return – it simply outputs a newline:

cr 100 . cr 200 . cr 300 .
<- Top

This will output:

cr 100 . cr 200 . cr 300 . 100 200 300 ok

." ( -- )

Finally we have ." – a special word for outputting strings. The ." word works differently inside definitions to interactive mode. ." marks the beginning of a string to output, and the end of the string is marked by ". The closing " isn’t a word, and so doesn’t need to be space-delimited. Here’s an example:

: say-hello  ." Hello there!" ;
<- Top

You should see the following output

say-hello Hello there! ok

We can combine .".cr, and emit to build up more complex output:

: print-stack-top  cr dup ." The top of the stack is " .
  cr ." which looks like '" dup emit ." ' in ascii  " ;
48 print-stack-top
<- Top

Running this should give you the following output:

48 print-stack-top The top of the stack is 48 which looks like ‘0’ in ascii ok

Conditionals and Loops

Now onto the fun stuff! Forth, like most other languages, has conditionals and loops for controlling the flow of your program. To understand how they work, however, first we need to understand booleans in Forth.


There’s actually no boolean type in Forth. The number 0 is treated as false, and any other number is true, although the canonical true value is -1 (all boolean operators return 0 or -1).

To test if two numbers are equal, you can use =:

3 4 = .
5 5 = .

This should output:

3 4 = . 0 ok 5 5 = . -1 ok
<- Top

You can use < and > for less than and greater than. < checks to see if the second item from the top of the stack is less than the top item of the stack, and vice versa for >:

3 4 < .
3 4 > .
3 4 < . -1 ok 3 4 > . 0 ok
<- Top

The boolean operators And, Or, and Not are available as andor, and invert:

3 4 < 20 30 < and .
3 4 < 20 30 > or .
3 4 < invert .

The first line is the equivalent of 3 < 4 & 20 < 30 in a C-based language. The second line is the equivalent of 3 < 4 | 20 > 30. The third line is the equivalent of !(3 < 4).

andor, and invert are all bitwise operations. For well-formed flags (0 and -1) they’ll work as expected, but they’ll give incorrect results for arbitrary numbers.

<- Top

if then

Now we can finally get onto conditionals. Conditionals in Forth can only be used inside definitions. The simplest conditional statement in Forth is if then, which is equivalent to a standard if statement in most languages. Here’s an example of a definition using if then. In this example, we’re also using the mod word, which returns the modulo of the top two numbers on the stack. In this case, the top number is 5, and the other is whatever was placed on the stack before calling buzz?. Therefore, 5 mod 0 = is a boolean expression that checks to see if the top of the stack is divisible by 5.

: buzz?  5 mod 0 = if ." Buzz" then ;
3 buzz?
4 buzz?
5 buzz?
<- Top

This will output:

3 buzz? ok 4 buzz? ok 5 buzz? Buzz ok

It’s important to note that the then word marks the end of the if statement. This makes it equivalent to fi in Bash or end in Ruby, for example.

Another important thing to realize is that if consumes the top value on the stack when it checks to see if it’s true or false.

if else then

if else then is equivalent to an if/else statement in most languages. Here’s an example of its use:

: is-it-zero?  0 = if ." Yes!" else ." No!" then ;
0 is-it-zero?
1 is-it-zero?
2 is-it-zero?
<- Top

This outputs:

0 is-it-zero? Yes! ok 1 is-it-zero? No! ok 2 is-it-zero? No! ok

This time, the if clause (consequent) is everything between if and else, and the else clause (alternative) is everything between else and then.

do loop

do loop in Forth most closely resembles a for loop in most C-based languages. In the body of a do loop, the special word i pushes the current loop index onto the stack.

The top two values on the stack give the starting value (inclusive) and ending value (exclusive) for the i value. The starting value is taken from the top of the stack. Here’s an example:

: loop-test  10 0 do i . loop ;
<- Top

This should output:

loop-test 0 1 2 3 4 5 6 7 8 9 ok

The expression 10 0 do i . loop is roughly equivalent to:

for (int i = 0; i < 10; i++) {

Fizz Buzz

We can write the classic Fizz Buzz program easily using a do loop:

: fizz?  3 mod 0 = dup if ." Fizz" then ;
: buzz?  5 mod 0 = dup if ." Buzz" then ;
: fizz-buzz?  dup fizz? swap buzz? or invert ;
: do-fizz-buzz  25 1 do cr i fizz-buzz? if i . then loop ;
<- Top

fizz? checks to see if the top of the stack is divisible by 3 using 3 mod 0 =. It then uses dup to duplicate this result. The top copy of the value is consumed by if. The second copy is left on the stack and acts as the return value of fizz?.

If the number on top of the stack is divisible by 3, the string "Fizz" will be output, otherwise there will be no output.

buzz? does the same thing but with 5, and outputs the string "Buzz".

fizz-buzz? calls dup to duplicate the value on top of the stack, then calls fizz?, converting the top copy into a boolean. After this, the top of the stack consists of the original value, and the boolean returned by fizz?swap swaps these, so the original top-of-stack value is back on top, and the boolean is underneath. Next we call buzz?, which replaces the top-of-stack value with a boolean flag. Now the top two values on the stack are booleans representing whether the number was divisible by 3 or 5. After this, we call or to see if either of these is true, and invert to negate this value. Logically, the body of fizz-buzz? is equivalent to:

!(x % 3 == 0 || x % 5 == 0)

Therefore, fizz-buzz? returns a boolean indicating if the argument is not divisible by 3 or 5, and thus should be printed. Finally, do-fizz-buzz loops from 1 to 25, calling fizz-buzz? on i, and outputting i if fizz-buzz? returns true.

If you’re having trouble figuring out what’s going on inside fizz-buzz?, the example below might help you to understand how it works. All we’re doing here is executing each word of the definition of fizz-buzz? on a separate line. As you execute each line, watch the stack to see how it changes:

: fizz?  3 mod 0 = dup if ." Fizz" then ;
: buzz?  5 mod 0 = dup if ." Buzz" then ;
<- Top

Here’s how each line affects the stack:

4         4 <- Top
dup       4 4 <- Top
fizz?     4 0 <- Top
swap      0 4 <- Top
buzz?     0 0 <- Top
or        0 <- Top
invert    -1 <- Top

Remember, the final value on the stack is the return value of the fizz-buzz? word. In this case, it’s true, because the number was not divisible by 3 or 5, and so should be printed.

Here’s the same thing but starting with 5:

5         5 <- Top
dup       5 5 <- Top
fizz?     5 0 <- Top
swap      0 5 <- Top
buzz?     0 -1 <- Top
or        -1 <- Top
invert    0 <- Top

In this case the original top-of-stack value was divisible by 5, so nothing should be printed.

Variables and Constants

Forth also allows you to save values in variables and constants. Variables allow you to keep track of changing values without having to store them on the stack. Constants give you a simple way to refer to a value that won’t change.


Because the role of local variables is generally played by the stack, variables in Forth are used more to store state that may be needed across multiple words.

Defining variables is simple:

variable balance

This basically associates a particular memory location with the name balancebalance is now a word, and all it does is to push its memory location onto the stack:

variable balance
<- Top

You should see the value 1000 on the stack. This Forth implementation arbitrarily starts storing variables at the memory location 1000.

The word ! stores a value at the memory location referenced by a variable, and the word @ fetches the value from a memory location:

variable balance
123 balance !
balance @
<- Top

This time you should see the value 123 on the stack. 123 balance pushes the value and the memory location onto the stack, and ! stores that value at that memory location. Likewise, @ retrieves the value based on the memory location, and pushes that value onto the stack. If you’ve used C or C++, you can think of balance as a pointer that is dereferenced by @.

The word ? is defined as @ . and it prints the current value of a variable. The word +! is used to increase the value of a variable by a certain amount (like += in C-based languages).

variable balance
123 balance !
balance ?
50 balance +!
balance ?
<- Top

Run this code and you should see:

variable balance ok 123 balance ! ok balance ? 123 ok 50 balance +! ok balance ? 173 ok


If you have a value that doesn’t change, you can store it as a constant. Constants are defined in one line, like this:

42 constant answer

This creates a new constant called answer with the value 42. Unlike variables, constants just represent values, rather than memory locations, so there’s no need to use @.

42 constant answer
2 answer *
<- Top

Running this will push the value 84 on the stack. answer is treated as if it was the number it represents (just like constants and variables in other languages).


Forth doesn’t exactly support arrays, but it does allow you to allocate a zone of contiguous memory, a lot like arrays in C. To allocate this memory, use the allot word.

variable numbers
3 cells allot
10 numbers 0 cells + !
20 numbers 1 cells + !
30 numbers 2 cells + !
40 numbers 3 cells + !
<- Top

This example creates a memory location called numbers, and reserves three extra memory cells after this location, giving a total of four memory cells. (cells just multiplies by the cell-width, which is 1 in this implementation.)

numbers 0 + gives the address of the first cell in the array. 10 numbers 0 + ! stores the value 10 in the first cell of the array.

We can easily write words to simplify array access:

variable numbers
3 cells allot
: number  ( offset -- addr )  cells numbers + ;

10 0 number !
20 1 number !
30 2 number !
40 3 number !

2 number ?
<- Top

number takes an offset into numbers and returns the memory address at that offset. 30 2 number ! stores 30 at offset 2 in numbers, and 2 number ? prints the value at offset 2 in numbers.

Keyboard Input

Forth has a special word called key, which is used for accepting keyboard input. When the key word is executed, execution is paused until a key is pressed. Once a key is pressed, the key code of that key is pushed onto the stack. Try out the following:

key . key . key .
<- Top

When you run this line, you’ll notice that at first nothing happens. This is because the interpreter is waiting for your keyboard input. Try hitting the A key, and you should see the keycode for that key, 65, appear as output on the current line. Now hit B, then C, and you should see the following:

key . key . key . 65 66 67 ok

Printing keys with begin until

Forth has another kind of loop called begin until. This works like a while loop in C-based languages. Every time the word until is hit, the interpreter checks to see if the top of the stack is non-zero (true). If it is, it jumps back to the matching begin. If not, execution continues.

Here’s an example of using begin until to print key codes:

: print-keycode  begin key dup . 32 = until ;
<- Top

This will keep printing key codes until you press space. You should see something like this:

print-keycode 80 82 73 78 84 189 75 69 89 67 79 68 69 32 ok

key waits for key input, then dup duplicates the keycode from key. We then use . to output the top copy of the keycode, and 32 = to check to see if the keycode is equal to 32. If it is, we break out of the loop, otherwise we loop back to begin.


Now it’s time to put it all together and make a game! Rather than having you type all the code, I’ve pre-loaded it into the editor.

Before we look at the code, try playing the game. To start the game, execute the word start. Then use the arrow keys to move the snake. If you lose, you can run start again.

<- Top

variable snake-x-head ok

500 cells allot ok


variable snake-y-head ok

500 cells allot ok


variable apple-x ok

variable apple-y ok


0 constant left ok

1 constant up ok

2 constant right ok

3 constant down ok


24 constant width ok

24 constant height ok


variable direction ok

variable length ok


: snake-x ( offset — address )

cells snake-x-head + ; ok


: snake-y ( offset — address )

cells snake-y-head + ; ok


: convert-x-y ( x y — offset ) 24 cells * + ; ok

: draw ( color x y — ) convert-x-y graphics + ! ; ok

: draw-white ( x y — ) 1 rot rot draw ; ok

: draw-black ( x y — ) 0 rot rot draw ; ok


: draw-walls

width 0 do

i 0 draw-black

i height 1 – draw-black


height 0 do

0 i draw-black

width 1 – i draw-black

loop ; ok


: initialize-snake

4 length !

length @ 1 + 0 do

12 i – i snake-x !

12 i snake-y !


right direction ! ; ok


: set-apple-position apple-x ! apple-y ! ; ok


: initialize-apple 4 4 set-apple-position ; ok


: initialize

width 0 do

height 0 do

j i draw-white





initialize-apple ; ok


: move-up -1 snake-y-head +! ; ok

: move-left -1 snake-x-head +! ; ok

: move-down 1 snake-y-head +! ; ok

: move-right 1 snake-x-head +! ; ok


: move-snake-head direction @

left over = if move-left else

up over = if move-up else

right over = if move-right else

down over = if move-down

then then then then drop ; ok


\ Move each segment of the snake forward by one ok

: move-snake-tail 0 length @ do

i snake-x @ i 1 + snake-x !

i snake-y @ i 1 + snake-y !

-1 +loop ; ok


: is-horizontal direction @ dup

left = swap

right = or ; ok


: is-vertical direction @ dup

up = swap

down = or ; ok


: turn-up is-horizontal if up direction ! then ; ok

: turn-left is-vertical if left direction ! then ; ok

: turn-down is-horizontal if down direction ! then ; ok

: turn-right is-vertical if right direction ! then ; ok


: change-direction ( key — )

37 over = if turn-left else

38 over = if turn-up else

39 over = if turn-right else

40 over = if turn-down

then then then then drop ; ok


: check-input

last-key @ change-direction

0 last-key ! ; ok


\ get random x or y position within playable area ok

: random-position ( — pos )

width 4 – random 2 + ; ok


: move-apple

apple-x @ apple-y @ draw-white

random-position random-position

set-apple-position ; ok


: grow-snake 1 length +! ; ok


: check-apple

snake-x-head @ apple-x @ =

snake-y-head @ apple-y @ =

and if



then ; ok


: check-collision ( — flag )

\ get current x/y position

snake-x-head @ snake-y-head @

\ get color at current position

convert-x-y graphics + @

\ leave boolean flag on stack

0 = ; ok


: draw-snake

length @ 0 do

i snake-x @ i snake-y @ draw-black


length @ snake-x @

length @ snake-y @

draw-white ; ok


: draw-apple

apple-x @ apple-y @ draw-black ; ok



: game-loop ( — )




100 sleep







.” Game Over” ; ok


: start initialize game-loop ; ok


Before we delve too deeply into this code, two disclaimers. First, this is terrible Forth code. I’m by no means a Forth expert, so there’s probably all kinds of things I’m doing in completely the wrong way. Second, this game uses a few non-standard techniques in order to interface with JavaScript. I’ll go through these now.

Non-Standard Additions

The Canvas

You may have noticed that this editor is different from the others: it has an HTML5 Canvas element built in. I’ve created a very simple memory-mapped interface for drawing onto this canvas. The canvas is split up into 24 x 24 “pixels” which can be black or white. The first pixel is found at the memory address given by the variable graphics, and the rest of the pixels are offsets from the variable. So, for example, to draw a white pixel in the top-left corner you could run

1 graphics !
<- Top

The game uses the following words to draw to the canvas:

: convert-x-y ( x y -- offset )  24 cells * + ;
: draw ( color x y -- )  convert-x-y graphics + ! ;
: draw-white ( x y -- )  1 rot rot draw ;
: draw-black ( x y -- )  0 rot rot draw ;

For example, 3 4 draw-white draws a white pixel at the coordinates (3, 4). The y coordinate is multiplied by 24 to get the row, then the x coordinated is added to get the column.

Non-Blocking Keyboard Input

The Forth word key blocks, so is unsuitable for a game like this. I’ve added a variable called last-key which always holds the value of the last key to be pressed. last-key is only updated while the interpreter is running Forth code.

Random Number Generation

The Forth standard doesn’t define a way of generating random numbers, so I’ve added a word called random ( range -- n ) that takes a range and returns a random number from 0 to range – 1. For example, 3 random could return 01, or 2.

sleep ( ms -- )

Finally, I’ve added a blocking sleep word that pauses execution for the number of milliseconds given.

The Game Code

Now we can work through the code from start to finish.

Variables and Constants

The start of the code just sets up some variables and constants:

variable snake-x-head
500 cells allot

variable snake-y-head
500 cells allot

variable apple-x
variable apple-y

0 constant left
1 constant up
2 constant right
3 constant down

24 constant width
24 constant height

variable direction
variable length

snake-x-head and snake-y-head are memory locations used to store the x and y coordinates of the head of the snake. 500 cells of memory are alloted after these two locations to store the coordinates of the tail of the snake.

Next we define two words for accessing memory locations representing the body of the snake.

: snake-x ( offset -- address )
  cells snake-x-head + ;

: snake-y ( offset -- address )
  cells snake-y-head + ;

Just like the number word earlier, these two words are used to access elements in the arrays of snake segments. After this come some words for drawing to the canvas, described above.

We use constants to refer to the four directions (leftupright, and down), and a variable direction to store the current direction.


After this we initialize everything:

: draw-walls
  width 0 do
    i 0 draw-black
    i height 1 - draw-black
  height 0 do
    0 i draw-black
    width 1 - i draw-black
  loop ;

: initialize-snake
  4 length !
  length @ 1 + 0 do
    12 i - i snake-x !
    12 i snake-y !
  right direction ! ;

: set-apple-position apple-x ! apple-y ! ;

: initialize-apple  4 4 set-apple-position ;

: initialize
  width 0 do
    height 0 do
      j i draw-white
  initialize-apple ;

draw-walls uses two do/loops to draw the horizontal and vertical walls, respectively.

initialize-snake sets the length variable to 4, then loops from 0 to length + 1 filling in the starting snake positions. The snake positions are always kept one longer than the length so we can grow the snake easily.

set-apple-position and initialize-apple set the initial position of the apple to (4,4).

Finally, initialize fills everything in white and calls the three initialization words.

Moving the Snake

Here’s the code for moving the snake based on the current value of direction:

: move-up  -1 snake-y-head +! ;
: move-left  -1 snake-x-head +! ;
: move-down  1 snake-y-head +! ;
: move-right  1 snake-x-head +! ;

: move-snake-head  direction @
  left over  = if move-left else
  up over    = if move-up else
  right over = if move-right else
  down over  = if move-down
  then then then then drop ;

\ Move each segment of the snake forward by one
: move-snake-tail  0 length @ do
    i snake-x @ i 1 + snake-x !
    i snake-y @ i 1 + snake-y !
  -1 +loop ;

move-upmove-leftmove-down, and move-right just add or subtract one from the x or y coordinate of the snake head. move-snake-head inspects the value of direction and calls the appropriate move-* word. This over = if pattern is an idiomatic way of doing case statements in Forth.

move-snake-tail goes through the array of snake positions backwards, copying each value forward by 1 cell. This is called before we move the snake head, to move each segment of the snake forward one space. It uses a do/+loop, a variation of a do/loop that pops the stack on every iteration and adds that value to the next index, instead of incrementing by 1 each time. So 0 length @ do -1 +loop loops from length to 0 in increments of -1.

Keyboard Input

The next section of code takes the keyboard input and changes the snake direction if appropriate.

: is-horizontal  direction @ dup
  left = swap
  right = or ;

: is-vertical  direction @ dup
  up = swap
  down = or ;

: turn-up     is-horizontal if up direction ! then ;
: turn-left   is-vertical if left direction ! then ;
: turn-down   is-horizontal if down direction ! then ;
: turn-right  is-vertical if right direction ! then ;

: change-direction ( key -- )
  37 over = if turn-left else
  38 over = if turn-up else
  39 over = if turn-right else
  40 over = if turn-down
  then then then then drop ;

: check-input
  last-key @ change-direction
  0 last-key ! ;

is-horizontal and is-vertical check the current status of the direction variable to see if it’s a horizontal or vertical direction.

The turn-* words are used to set a new direction, but use is-horizontal and is-vertical to check the current direction first to see if the new direction is valid. For example, if the snake is moving horizontally, setting a new direction of left or right doesn’t make sense.

change-direction takes a key and calls the appropriate turn-* word if the key was one of the arrow keys. check-input does the work of getting the last key from the last-key pseudo-variable, calling change-direction, then setting last-key to 0 to indicate that the most recent keypress has been dealt with.

The Apple

The next code is used for checking to see if the apple has been eaten, and if so, moving it to a new (random) location. Also, if the apple has been eaten we grow the snake.

\ get random x or y position within playable area
: random-position ( -- pos )
  width 4 - random 2 + ;

: move-apple
  apple-x @ apple-y @ draw-white
  random-position random-position
  set-apple-position ;

: grow-snake  1 length +! ;

: check-apple ( -- flag )
  snake-x-head @ apple-x @ =
  snake-y-head @ apple-y @ =
  and if
  then ;

random-position generates a random x or y coordinate in the range of 2 to width - 2. This prevents the apple from ever appearing right next to the wall.

move-apple erases the current apple (using draw-white) then creates a new pair of x/y coordinates for the apple using random-position twice. Finally, it calls set-apple-position to move the apple to the new coordinates.

grow-snake simply adds one to the length variable.

check-apple compares the x/y coordinates of the apple and the snake head to see if they’re the same (using = twice and and to combine the two booleans). If the coordinates are the same, we call move-apple to move the apple to a new position and grow-snake to make the snake 1 segment longer.

Collision Detection

Next we see if the snake has collided with the walls or itself.

: check-collision ( -- flag )
  \ get current x/y position
  snake-x-head @ snake-y-head @

  \ get color at current position
  convert-x-y graphics + @

  \ leave boolean flag on stack
  0 = ;

check-collision checks to see if the new snake head position is already black (this word is called after updating the snake’s position but before drawing it at the new position). We leave a boolean on the stack to say whether a collision has occured or not.

Drawing the Snake and Apple

The next two words are responsible for drawing the snake and apple.

: draw-snake
  length @ 0 do
    i snake-x @ i snake-y @ draw-black
  length @ snake-x @
  length @ snake-y @
  draw-white ;

: draw-apple
  apple-x @ apple-y @ draw-black ;

draw-snake loops through each cell in the snake arrays, drawing a black pixel for each one. After that it draws a white pixel at an offset of length. The last part of the tail is at length - 1 into the array so length holds the previous last tail segment.

draw-apple simply draws a black pixel at the apple’s current location.

The Game Loop

The game loop constantly loops until a collision occurs, calling each of the words defined above in turn.

: game-loop ( -- )
    100 sleep
  ." Game Over" ;

: start  initialize game-loop ;

The begin/until loop uses the boolean returned by check-collision to see whether to continue looping or to exit the loop. When the loop is exited the string "Game Over" is printed. We use 100 sleep to pause for 100 ms every iteration, making the game run at rougly 10 fps.

start just calls initialize to reset everything, then kicks off game-loop. Because all the initialization happens in the initialize word, you can call start again after game over.

And that’s it! Hopefully all the code in the game made sense. If not, you can try running individual words to see their effect on the stack and/or on the variables.

The End

Forth is actually much more powerful than what I’ve taught here (and what I implemented in my interpreter). A true Forth system allows you to modify how the compiler works and create new defining words, allowing you to completely customize your environment and create your own languages within Forth.

A great resource for learning the full power of Forth is the short book “Starting Forth” by Leo Brodie. It’s available for free online and teaches you all the fun stuff I left out. It also has a good set of exercises for you to test out your knowledge. You’ll need to download a copy of SwiftForth to run the code though.

 Posted by at 6:11 am
Apr 022020


 Posted by at 7:37 am
Apr 022020




original link

Here is a list of pdf document files and zipped software items from Offete Store which are now available for download. Please contact the author, CH Ting, if you have any questions about this material.

Inside Forth – Fourth Edition – 2013 – pdf

Systems Guide to figForth – Third Edition – 2013 – pdf

eForth and Zen – Second Edition – 2013 – pdf

Footsteps in an Empty Valley – NC4000 Single Chip Forth Engine – Third Expanded Edition – 1988 – pdf

Footsteps in an Empty Valley – NC4000 Single Chip Forth Engine – Fourth Edition – 2017 – pdf

F# – 241 – zip

ADUC Compiler – 520 – zip

eForth for SAM7 Chip – 2008 – zip

cEF, eForth in C, Version 1.1 – 2009 – zip

cEF, eForth in C – 2009 – zip

eForth for STM8S – 2010 – zip

eP32 Microcontroller Design in VHDL – 2012 – zip

328eForth for Arduino Uno – 2011– zip

eForth as an Arduino Sketch, Version 2.0 – 2011 – zip

eP16 Microcontroller Design in VHDL – 2012 – zip

430eForth for LaunchPad – 2012 – zip

STM32 eForth – 2014 – zip

Zen of LaunchPad – Version 4.3 – 2015 – zip

86eForth – Version 2.03 – 2016 – zip

ep8080 – 2006 – zip

PDP1 Design Workshop – 2016 – zip

86eForth – Version 5.2 – 2016 – zip

espForth for ESP8266 – zip

ceForth_23 – zip

esp32Forth Serial Monitor – zip

esp32Forth Web Browser – zip

esp32Forth Macro Assembler – zip

ceForth_33 Macro Assembler – zip

Many thanks to Dr. Ting for being one of the best authors and teachers of Forth ! and for his gesture setting all those important documents free available !

 Posted by at 7:28 am
Mar 312020


Unexpected stories about creativity
Told by WeTransfer

Arif Al Nomay I just want the world to know about us

When a power cut and a computer malfunction caused Yemeni photographer Arif Al Nomay to lose years of work, he anxiously hunted for anything that might still be there. To his surprise, a set of photos taken at a Summer Festival in his country’s capital had survived, but they had been altered, their colors skewed and the details hard to distinguish. Since the festival took place the year before Yemen descended into war, the series would become a symbol for the pieces of everyday life that were lost as a result.

Words by Alex Kahl.

In 2014 Arif Al Nomay traveled with his camera to a park called The Seventy in Sanaa, the capital city of his home country of Yemen. He had been hired to take photographs at an annual festival, a celebration of the heritage that characterizes many of the country’s different regions.

 Posted by at 1:02 pm
Mar 242020


Welcome to the article collection. All articles here can be edited by everyone according to the wiki principle. To the main page of the article collection


From the article collection, with contributions from various authors (see version history)

Problem Description

Mechanical live components such as switches and buttons tend to bounce when switched on and off , ie they quickly switch off and on several times, which is caused by mechanical vibrations of the switch contact, unless they are protected against it with complex mechanical measures. The encoders in particular are sensitive to this due to the detent positions and the movement of the operator. Optoelectronic components and chemical contact switches as well as liquid switches also have the problem.

Simply put, a voltage switched by a bouncing switch or button looks like this: Entprellen.png

There are therefore several short switch-on pulses, which can be interpreted as multiple commands for push buttons and as wrong angular movements for rotary encoders. With switches, on the other hand, there are several resets and switch-on processes in the electronic assembly, which draw power unnecessarily or, in the worst case, stress or damage the circuit. Important switches and those that are supposed to carry high currents are protected by suitable measures such as redundancy, tap changer concepts or, in the case of gas and liquid switches, by electrochemical measures. This is saved with simple switches.

Since there is no safe way to avoid these effects with these simple, unprotected switches, the wrong signal must be evaluated sensibly by the electronics. There are different approaches for this:


Bounce-free switches

As already indicated, the electromechanical industry has various special constructions for special applications that generate clean switching states to the outside by using either mechanical damping in the form of a self-locking spring mechanism or an integrated electronic signal delay. However, such systems are expensive and are mostly used only in the performance range. In addition, they are not 100% safe and fail due to aging. Wherever possible, further measures are therefore taken to suppress bouncing.

Changeover switch

A classic RS flip-flop can be used to debounce toggle switches . In this variant, in addition to two NAND gates, only two pull-up resistors are required.

Debounce buttons with NAND-RS flip-flop

In the switch position shown, level 0 is present at position / S. This sets the flip-flop and the output at level 1. If the switch between contacts 2 and 3 closes, level 0 is present at position / R. This means that the output of the flip-flop goes to level 0. As soon as the switch changes from one contact to the other, it usually begins to bounce. During the bouncing, the switch switches between the two states “switch touches contact” and “switch is free in the air”. The output of the flip-flop remains stable during this bounce time, since the switch never touches the opposite contact during the bounce and the RS flip-flop can keep its state alone. The bounce time is strongly dependent on the switch type and is between 0.1 and 10ms. The dimensioning of the resistors is relatively uncritical. 100kOhm can be used as a guideline.

Toggle switch without flip-flop

If you don’t have a flip-flop at hand, you can also use this circuit.

Changer debounce with capacitor

How it works: When switching, the capacitor is always immediately recharged. While the contact bounces, it is in the air and has no connection. During this time, the capacitor maintains the level.

Dimensioning: If the debounced button is connected to an IC, the input leakage current is the decisive current. If further currents flow, these must be taken into account. With a microcontroller from Atmel, 1µA is typical. The following applies:


Since a bruise lasts about 10ms and the voltage should drop by a maximum of 0.5V during this time, the following capacity is reached:

C=IdtdU=1μA10ms0,5V20 F

A resistor can be added to reduce current peaks. A time constant of 1µs to 1ms seems reasonable. So 500 Ohm to 500kOhm can be used, whereby the current peaks are higher at low resistance, and the pin current becomes disruptive at 500kOhm.

Simple button

Even if the RS flip-flop is very effective, this variant of the debouncing is rarely used. The reason for this is that simple switches are used more often in circuits. These are often smaller and cheaper. To debounce simple push buttons / momentary switch, a simple RC low pass can be used. A capacitor is charged or discharged via a resistor depending on the switch position. The RC element forms a low pass, so that the voltage across the capacitor cannot jump from one level to the other.

Debounce buttons with RC debouncer

Emerging voltage curve

When the switch is open, the capacitor slowly charges to V cc through the two resistors R 1 and R 2 . When the switchover threshold is reached, the output jumps to level 0. If the switch is closed, the capacitor slowly discharges through resistor R 2 . Accordingly, the output of the inverter changes to level 1. While the button is bouncing, the voltage across the capacitor cannot change abruptly, since the charging and discharging takes place rather slowly via the resistors. In addition, the switching thresholds for the transition LOW-> HIGH and HIGH-> LOW are very different (hysteresis, see article Schmitt trigger). If the components are dimensioned correctly, the output of the inverter is thus free of bounce.

Please note that the inverter must be one with Schmitt trigger inputs, because the output is not defined for standard logic inputs in the range of typically 0.8V – 2.0V. For example, the 74HC14 or CD40106 (pin compatible) can be used as an inverter. Alternatively, a CD4093 can be used. The CD4093 is a NAND gate with Schmitt trigger inputs. To make an inverter out of a NAND gate, simply connect the two inputs or set one input to HIGH.

For a suitable dimensioning you have to juggle something with the standard formulas for a capacitor. The voltage across the capacitor during discharge is calculated according to:


For the output of the inverter to be stable, the voltage across the capacitor and thus the voltage at the input of the inverter must remain above the voltage at which the inverter switches. This threshold voltage is exactly the time-dependent voltage across the capacitor.

UC(t) Uth

By changing the formula:

R2=tC1⋅ UthU0)

A button usually bounces about 10ms. For safety reasons, a bounce time of 20ms can be assumed when calculating the resistance. U_0 is the operating voltage Vcc. The threshold voltage must be read from the data sheet of the Schmitt trigger used. The 74HC14 has a value of 2.0V. If you take 1µF for the capacitor and the operating voltage is 5V, the resistance is about 22kOhm.

If the switch is opened, the capacitor charges according to the following formula:


With U_th = U_C, the changeover to (R_1 + R_2) results in:

R1+R2=tC1⋅ ( 1 – UthU0)

A value of 2.3V can be read from the data sheet for the threshold voltage. With this value and the assumptions from above there is a value of 32kOhm for R_1 + R_2. This results in a value of approximately 10 kOhm for R_1.

Note: For Hitachi 74LS14 e.g. B. the upper and lower switching threshold values are different. Care must be taken that U_ {th} takes the lower threshold when unloading and U_ {th} takes the upper threshold when loading.


In times of electronic evaluation of buttons and switches, debouncing software is often cheaper than using an expensive switch. For this reason, computer keyboards, for example, are no longer equipped with low-bounce keys or debounce capacitors.

If you use the microcontroller that is already available in most devices, for example, you can save yourself the additional hardware, since debouncing in software works practically just as well. It should only be noted that additional computing power and, depending on the implementation, some hardware resources (eg timers) are required. But you have the advantage of short pulses, which obviously can not be a key press but z. B. caused by stray, easy to filter.

Edge detection

There are 4 theoretical states for a push button:

  • 1. was not pressed and is not pressed
  • 2. was not pressed and is pressed (rising edge)
  • 3. was pressed and is still pressed
  • 4. was pressed and is no longer pressed (falling edge)

These individual states can now be easily queried / run through. The debouncing takes place through the entire duration of the program. The buttons are connected as active low to use the internal pull-ups.

This routine returns the value “1” for the “rising edge” state, otherwise “0”


char taster(void)
    static unsigned char zustand;
    char rw = 0;

    if ( state  ==  0  &&  ! ( KEY PORT  &  ( 1 << KEYBIT )))    // key is pressed (rising edge) 
        state  =  1 ; 
        rw  =  1 ; 
    else  if  ( state  ==  1  &&  ! ( BUTTON PORT  &  ( 1 << BUTTON BIT )))    // button is held 
         state  =  2 ; 
         rw  =  0; 
    else  if  ( state  ==  2  &&  ( KEY PORT  &  ( 1 << KEYBIT )))    // 
    key is released (falling edge) { 
        state  =  3 ; 
        rw  =  0 ; 
    else  if  ( state  ==  3  &&  ( BUTTON PORT  &  ( 1 << BUTTON BIT )))    // button released 
        state  =  0 ; 
        rw  = 0;

    return rw;

An extension so that a button is recognized for as long as required can be implemented very simply as follows:

    // state can either be detected as held for the first time or every other time 
    else  if  ((( state  ==  1 )  ||  ( state  ==  2 ))  &&  ! ( TASTERPORT  &  ( 1 << TASTERBIT )))    / / Button is held 
         state  =  2 ; 
         rw  =  0 ; 

On hold procedure

If a microcontroller is to be used to count how often a contact or a relay is switched, the bouncing of the contact must be taken into account precisely – and differentiated from a desired multiple switching, as otherwise incorrect impulses may be counted or real switching processes may be skipped. This must be taken into account when writing the program with regard to scanning the contact.

In the following simple example of a debouncing, it should be noted that the AVR waits 200ms when a button is pressed, i.e. lies idle. A different method should be used for time-critical applications (e.g. querying the key states in a timer interrupt service routine).

#include <avr/io.h>
#include <inttypes.h>
#ifndef F_CPU 
#warning "F_CPU was not yet defined, is now defined with 3686400" 
#define F_CPU 3686400UL      / * quartz with 3.6864 Mhz * /
#include <util/delay.h>     /* bei alter avr-libc: #include <avr/delay.h> */      

/ * Simple function for debouncing a button * / 
inline  uint8_t  debounce ( volatile  uint8_t  * port ,  uint8_t  pin ) 
    if  (  ! ( * Port  &  ( 1  <<  pin ))  ) 
        / * pin was pulled to ground, wait 100ms * / 
        _delay_ms ( 50 );    // maximum value of the parameter at _delay_ms 
        _delay_ms ( 50 );    // note, cf. Documentation of the avr-libc 
        if  (  * port &  ( 1  <<  pin )  ) 
            / * Give user time to release the button * / 
            _delay_ms ( 50 ); 
            _delay_ms ( 50 );  
            return  1 ; 
    return  0 ; 

int  main ( void ) 
    DDRB  & =  ~ (  1  <<  PB0  );         / * PIN PB0 on input push button) * / 
    PORTB  | =  (  1  <<  PB0  );         / * Activate pull-up resistor * / 
    if  ( debounce ( & PINB ,  PB0 )) 
        / * If button on PIN PB0 is pressed * / 
        / * Switch LED on or off at port PD7: * / 
        PORTD  =  PORTD  ^  (  1  <<  PD7  ); 

Unfortunately, the above routine has several disadvantages:

  • it only detects letting go (unergonomic)
  • it always delays the main loop by 100ms when the button is pressed
  • it loses keystrokes the more the mainloop has to do.

A similarly easy-to-use routine, but without all of these disadvantages, can be found in the forum thread debouncing for beginners

The DEBOUNCE command in the BASIC dialect BASCOM for AVR is also programmed according to the hold pattern method. The waiting time is 25 ms as standard, but can be overwritten by the user. See BASCOM online manual for DEBOUNCE .

A C implementation for a key query with a hold pattern can be found in the article AVR-GCC-Tutorial: IO registers as parameters and variables .

The disadvantage of this method is that the controller is blocked by the waiting loop. Implementation with a timer interrupt is cheaper.

Waiting loop variant with mask and pointer (according to Christian Riggenbach)

Here is another function for debouncing buttons: With the additional code, a debouncing time of 1-3ms on average (at least 8 * 150µs = 1ms) can be achieved. Basically, the function checks the level of the pins on a specific port. If the level was constant 8 times, the loop is exited. This function can be used very well to request buttons in an infinite loop because, as mentioned, it has a short waiting time.

void entprellung( volatile uint8_t *port, uint8_t maske ) {
  uint8_t   port_puffer;
  uint8_t   entprellungs_puffer;

  for( entprellungs_puffer=0 ; entprellungs_puffer!=0xff ; ) {
    port_puffer = *port;
    if( (*port & maske) == (port_puffer & maske) )
      entprellungs_puffer |= 0x01;

The function is called as follows:

  // Bugfix 20100414 
  debouncing (  & PINB ,  ( 1 << PINB2 )  );  // wait for bouncing 
  if necessary (  PINB  &  ( 1 << PINB2 )  )            // then read in a stable value 
    // do something 
  else } 
  { // do something else }

Any value can be transferred as a mask. It prevents buttons that are not used from negatively influencing the debounce time.

Debounce macro by Peter Dannegger

Peter Dannegger described the following simplified debouncing procedure in “Debouncing for Beginners” . The macro works in the original version with active low switches, but can be easily adapted for active high switches ( Tasty Reloaded ).

/*                                                                      */
/*                      Not so powerful Debouncing Example              */
/*                      No Interrupt needed                             */
/*                                                                      */
/*              Author: Peter Dannegger                                 */
/*                                                                      */
// Target: ATtiny13

#include <avr/io.h>
#define F_CPU 9.6e6
#include <util/delay.h>

#define debounce( port, pin )                                         \
({                                                                    \
  static uint8_t flag = 0;     /* new variable on every macro usage */  \
  uint8_t i = 0;                                                      \
  if( flag ){                  /* check for key release: */           \
    for(;;){                   /* loop ... */                         \
      if( !(port & 1<<pin) ){  /* ... until key pressed or ... */     \
        i = 0;                 /* 0 = bounce */                       \
        break;                                                        \
      }                                                               \
      _delay_us( 98 );         /* * 256 = 25ms */                     \
      if( --i == 0 ){          /* ... until key >25ms released */     \
        flag = 0;              /* clear press flag */                 \
        i = 0;                 /* 0 = key release debounced */        \
        break;                                                        \
      }                                                               \
    }                                                                 \
  }else{                       /* else check for key press: */        \
    for(;;){                   /* loop ... */                         \
      if( (port & 1<<pin) ){   /* ... until key released or ... */    \
        i = 0;                 /* 0 = bounce */                       \
        break;                                                        \
      }                                                               \
      _delay_us( 98 );         /* * 256 = 25ms */                     \
      if( --i == 0 ){          /* ... until key >25ms pressed */      \
        flag = 1;              /* set press flag */                   \
        i = 1;                 /* 1 = key press debounced */          \
        break;                                                        \
      }                                                               \
    }                                                                 \
  }                                                                   \
  i;                           /* return value of Macro */            \

int main(void)
  DDRB  &= ~(1<<PB0);
  PORTB |=   1<<PB0;
  DDRB  |=   1<<PB2;
  DDRB  &= ~(1<<PB1);
  PORTB |=   1<<PB1;
  DDRB  |=   1<<PB3;
    if( debounce( PINB, PB1 ) )
      PORTB ^= 1<<PB2;
    if( debounce( PINB, PB0 ) )
      PORTB ^= 1<<PB3;

If the macro for the same key (pin) is to be called up in several places, a function must be created so that both calls evaluate the same state variable flag [1] :

// Hilfsfunktion
uint8_t debounce_C1( void )
  return debounce(PINC, PC1);

// Beispielanwendung
int main(void)
  DDRB  |=   1<<PB2;
  DDRB  |=   1<<PB3;
  DDRC  &= ~(1<<PC1);
  PORTC |=   1<<PC1; // Pullup für Taster

    if( debounce_C1() )  // nicht: debounce(PINC, PC1)
      PORTB ^= 1<<PB2;
    if( debounce_C1() )  // nicht: debounce(PINC, PC1)
      PORTB ^= 1<<PB3;

Timer procedure (according to Peter Dannegger)

Grundroutine (AVR Assembler)

See also: Forum


  • particularly short code
  • fast

In addition, 8 buttons (active low) can be processed at the same time, so they can all be pressed at exactly the same time. Other routines can e.g. B. only process one key, ie the first or last pressed key wins, or it comes out nonsense.

The actual reading and debouncing routine is only 8 instructions short. The debounced key state is in the key_state register . With only 2 further instructions, the change from key open to key pressed is recognized and stored in the key_press register . In the example code, 8 LEDs are then switched on and off. Each key corresponds to a bit in the registers, ie processing is done bit by bit with logical operations. For understanding, it is therefore advisable to paint the logic equations with gates for one bit = one key. The registers can be thought of as flip-flops that work with the debounce time as a clock. Ie you can do it z. B. in a GAL22V10.

In addition to the individual instructions, all 8 possible combinations of the 3 signals are shown as comments.

Example code for AVR (assembler):

.include "c:\avr\inc\"
.def  save_sreg         = r0
.def  iwr0              = r1
.def  iwr1              = r2

.def  key_old           = r3
.def  key_state         = r4
.def  key_press         = r5

.def  leds              = r16
.def  wr0               = r17

.equ  key_port          = pind
.equ  led_port          = portb

      rjmp   init
.org OVF0addr		;timer interrupt 24ms
      in     save_sreg, SREG
get8key:                               ;/old      state     iwr1      iwr0
      mov    iwr0, key_old             ;00110011  10101010            00110011
      in     key_old, key_port         ;11110000
      eor    iwr0, key_old             ;                              11000011
      com    key_old                   ;00001111
      mov    iwr1, key_state           ;                    10101010
      or     key_state, iwr0           ;          11101011
      and    iwr0, key_old             ;                              00000011
      eor    key_state, iwr0           ;          11101000
      and    iwr1, iwr0                ;                    00000010
      or     key_press, iwr1           ;store key press detect
;			insert other timer functions here
      out    SREG, save_sreg
      ldi wr0, 0xFF
      out    ddrb, wr0
      ldi    wr0, 1<<CS02 | 1<<CS00    ;divide by 1024 * 256
      out    TCCR0, wr0
      ldi    wr0, 1<<TOIE0             ;enable timer interrupt
      out    TIMSK, wr0

      clr    key_old
      clr    key_state
      clr    key_press
      ldi    leds, 0xFF
main: cli
      eor    leds, key_press           ;toggle LEDs
      clr    key_press                 ;clear, if key press action done
      out    led_port, leds
      rjmp   main

Comfort routine (C for AVR)

See also: Forum

Note If instead of active-low (hibernation high) active-high (hibernation low) is used, a line must be changed see: entire post in the forum , position 1 in the post , ( position 2 in the post * does not have to be changed, since here the polarity has no influence).

Note 2 For initialization see forum

Functional principle as above plus additional features:

  • Can save keys by different actions with short or long press
  • Repeat function, e.g. B. for entering values

The program is written for avr-gcc / avr-libc, but can also be used with other compilers and microcontrollers with a few adjustments. A port for the AT91SAM7 can be found here (from the ARM MP3 / AAC Player project ).

/*                                                                      */
/*                      Debouncing 8 Keys                               */
/*                      Sampling 4 Times                                */
/*                      With Repeat Function                            */
/*                                                                      */
/*              Author: Peter Dannegger                                 */
/*                                              */
/*                                                                      */

#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>

#ifndef F_CPU
#define F_CPU           1000000                   // processor clock frequency
#warning kein F_CPU definiert
#define KEY_DDR         DDRB
#define KEY_PORT        PORTB
#define KEY_PIN         PINB
#define KEY0            0
#define KEY1            1
#define KEY2            2
#define ALL_KEYS        (1<<KEY0 | 1<<KEY1 | 1<<KEY2)
#define REPEAT_MASK     (1<<KEY1 | 1<<KEY2)       // repeat: key1, key2
#define REPEAT_START    50                        // after 500ms
#define REPEAT_NEXT     20                        // every 200ms

#define LED_DDR         DDRA
#define LED_PORT        PORTA
#define LED0            0
#define LED1            1
#define LED2            2
volatile uint8_t key_state;                                // debounced and inverted key state:
                                                  // bit = 1: key pressed
volatile uint8_t key_press;                                // key press detect
volatile uint8_t key_rpt;                                  // key long press and repeat
ISR( TIMER0_OVF_vect )                            // every 10ms
  static uint8_t ct0 = 0xFF, ct1 = 0xFF, rpt;
  uint8_t i;
  TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5);  // preload for 10ms
  i = key_state ^ ~KEY_PIN;                       // key changed ?
  ct0 = ~( ct0 & i );                             // reset or count ct0
  ct1 = ct0 ^ (ct1 & i);                          // reset or count ct1
  i &= ct0 & ct1;                                 // count until roll over ?
  key_state ^= i;                                 // then toggle debounced state
  key_press |= key_state & i;                     // 0->1: key press detect
  if( (key_state & REPEAT_MASK) == 0 )            // check repeat function
     rpt = REPEAT_START;                          // start delay
  if( --rpt == 0 ){
    rpt = REPEAT_NEXT;                            // repeat delay
    key_rpt |= key_state & REPEAT_MASK;
// check if a key has been pressed. Each pressed key is reported
// only once
uint8_t get_key_press( uint8_t key_mask )
  cli();                                          // read and clear atomic !
  key_mask &= key_press;                          // read key(s)
  key_press ^= key_mask;                          // clear key(s)
  return key_mask;
// check if a key has been pressed long enough such that the
// key repeat functionality kicks in. After a small setup delay
// the key is reported being pressed in subsequent calls
// to this function. This simulates the user repeatedly
// pressing and releasing the key.
uint8_t get_key_rpt( uint8_t key_mask )
  cli();                                          // read and clear atomic !
  key_mask &= key_rpt;                            // read key(s)
  key_rpt ^= key_mask;                            // clear key(s)
  return key_mask;

// check if a key is pressed right now
uint8_t get_key_state( uint8_t key_mask )

  key_mask &= key_state;
  return key_mask;

uint8_t get_key_short( uint8_t key_mask )
  cli();                                          // read key state and key press atomic !
  return get_key_press( ~key_state & key_mask );
uint8_t get_key_long( uint8_t key_mask )
  return get_key_press( get_key_rpt( key_mask ));
int main( void )
  LED_PORT = 0xFF;
  LED_DDR = 0xFF;                     

  // Configure debouncing routines
  KEY_DDR &= ~ALL_KEYS;                // configure key port for input
  KEY_PORT |= ALL_KEYS;                // and turn on pull up resistors

  TCCR0 = (1<<CS02)|(1<<CS00);         // divide by 1024
  TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5);  // preload for 10ms
  TIMSK |= 1<<TOIE0;                   // enable timer interrupt

  be ();

    if( get_key_short( 1<<KEY1 ))
      LED_PORT ^= 1<<LED1;
    if( get_key_long( 1<<KEY1 ))
      LED_PORT ^= 1<<LED2;
    // single press and repeat
    if( get_key_press( 1<<KEY2 ) || get_key_rpt( 1<<KEY2 )){
      uint8_t i = LED_PORT;
      i = (i & 0x07) | ((i << 1) & 0xF0);
      if( i < 0xF0 )
        i |= 0x08;
      LED_PORT = i;      

The single-press-and-repeat example does not work in every circuit; the following example should be more universal (single LED on / off):

// single press and repeat
if( get_key_press( 1<<KEY2 ) || get_key_rpt( 1<<KEY2 ))
    LED_PORT ^=0x08;

Newer variant that allows the following functions for a button:

- get_key_press()
- get_key_rpt()
- get_key_press() mit get_key_rpt()
- get_key_short() mit get_key_long()
- get_key_short() mit get_key_long_r() und get_key_rpt_l()

Extension for the detection of two buttons pressed simultaneously:

- get_key_common()

The code is based on 8 parallel vertical counters, which are built up via the variables ct0 and ct1

8 vertical counters in 2 8-bit variables

where each bit in ct0 together with the equivalent bit in ct1 forms a 2-bit counter. The code that takes care of the 8 counters is written so that it treats all 8 counters together in parallel.

  i = key_state ^ ~KEY_PIN;                       // key changed ?

At this point, i contains a 1 bit for each key that has changed compared to the previous debounced state (keystate).

  ct0 = ~( ct0 & i );                             // reset or count ct0
  ct1 = ct0 ^ (ct1 & i);                          // reset or count ct1

These two instructions decrease the 2-bit counter ct0 / ct1 by 1 for each bit that is set in i. If there is a 0 bit in the corresponding position in i (no change in status), the counter ct0 / ct1 is set to 1 for this bit. The basic state of the counter is as ct0 == 1 and ct1 == 1 (value 3). The counter therefore counts with every ISR call in which the key was identified as having changed compared to keystate

  ct1 ct0
    1    1   // 3
    1    0   // 2
    0    1   // 1
    0    0   // 0
    1    1   // 3
  i &= ct0 & ct1;                                 // count until roll over ?

A 1 bit is only retained in i where a 1 bit is found in both ct1 and ct0, ie the counter in question could count to 3. The additional rounding with i intercepts the case where a constant counter value of 3 in i leaves a 1 bit. In the end, this means that only a counter change from 0 to 3 leads to a 1 bit at the relevant point in i, but only if there was also a 1 bit in i at this bit position (which in turn was 1 because: a change to the last known debounced state was found at this input port). All in all, this means that a key press is recognized when the key is found 4 times in a row in a different state than the last known debounced key state.

At this point i is therefore a vector of 8 bits, each of which provides information as to whether the corresponding key was found several times in succession in the same state that does not match the last known key state. If this is the case, a corresponding change in the key status is registered in key_state

  key_state ^= i;                                 // then toggle debounced state

and if the corresponding bit in key_state has changed from 0 to 1, this event is evaluated as ‘key has been depressed’.

  key_press |= key_state & i;                     // 0->1: key press detect

This debounces the key input. This applies both when a key is pressed and when it is released (so that the bouncer is not confused with the depression of a key when released). The rest of the code then only deals with the further processing of this debounced key state.

The code part looks relatively complex due to the use of the many bitwise operations. But if you keep in mind that some of the bit-wise like a ‘parallel if’ are used simultaneously on all 8 bits, a lot will be simplified. On

    key_press |= key_state & i;

is nothing more than one

    // test whether bit 0 is set in both key_state and i 
    // and set bit 0 in key_press if this is the case 
    if (  (  key_state  &  (  1  <<  0  )  )  && 
        (  i  &  (  1  <<  0  )  ) 
       key_press  | =  (  1  <<  0  );

    // Bit 1
    if( ( key_state & ( 1 << 1 ) ) &&
        ( i & ( 1 << 1 ) )
       key_press |= ( 1 << 1 );

    // Bit 2
    if( ( key_state & ( 1 << 2 ) ) &&
        ( i & ( 1 << 2 ) )
       key_press |= ( 1 << 2 );


only performed as a much more compact operation and for all 8 bits simultaneously. The brevity and efficiency of these few lines of code results from the fact that each bit in the variables stands for a key and all 8 (maximum possible) keys go through the operations simultaneously.

How the different modes work is explained using timelines:

“Walkthrough” of the different states of the individual variables by pressing a button (

Reduced to just 1 button

Discussions in the forum show again and again that many dislike this code because it seems very complicated.

The code is not easy to analyze and pulls out all the stops to save both runtime and memory usage. You often hear the argument: I only need a debouncing for 1 button, is there anything easier?

Here is the ‘long form’ of the code, as you would write for just 1 key if you used the exact same debouncing method. You can see: There is no witchcraft involved: the last known debounced state of the key is held in key_state. The pin input is compared to this state and if the two differ, a counter is counted down. If this counts down produces an underflow of the counter, the key is considered debounced and if the key is also pressed then this is noted accordingly in key_press.

uint8_t key_state;
uint8_t key_counter;
volatile uint8_t key_press;

ISR( ... Overflow ... )
  uint8_t input = KEY_PIN & ( 1 << KEY0 );

  if( input != key_state ) {
    if( key_counter == 0xFF ) {
      key_counter = 3;
      key_state = input;
      if( input )
        key_press = TRUE;
    key_counter = 3;


uint8_t get_key_press()
  uint8_t result;

  result = key_press;
  key_press = FALSE;

  return result;

However, the complete debounce code, as listed above, now impresses in that it is compiled smaller than this more descriptive variant for only 1 key. And all this with increased functionality. Because e.g. an autorepeat is not yet built into this code. And at the latest when you want to debounce a 2nd key, the SRAM memory consumption of this long form is higher than that of the original for 8 keys. It follows that even for just 1 key, the original routine is the better choice.

And because of the complexity, one question: Are you able to write an efficient sqrt () function like the one you find in the standard C library? No? Then, according to your reasoning, you shouldn’t actually use the library function sqrt (), instead you would have to write a root function yourself.

Self-saturating filter (after Jürgen Schuhmacher)

By using discrete signal analysis in software, the functionality of a simple debouncing with a resistor, a capacitor and a Schmitt trigger can be simulated as in hardware by using an abstract IIR filter that emulates a capacitor charging curve. With the rule Y (t) = k Y (t-1) + input, a simple filter is generated that sluggishly follows the input value. If a certain value is exceeded, the output signal is switched with a simple query.

For assembler and VHDL with FPGAs, the following representation is suitable due to the easy-to-implement binary operations with a resolution of the filter value memory of only 8 bits: Value_New = Value_Alt – Value_Alt / 16 + 16 * (key = True). The filter value then maps the attenuated course of the input (flanked) and can suppress bouncing up to the limit for fast touching. The output value is then simply the most significant bit of the filter value.

Debouncing with IIR filter.gif

To do this, the signal from the button should ideally be sampled 10-20 times faster than the highest desired typing speed. It is possible to scan even faster, but it leads to more bits being required for the filter. The Schmittrigger function can be formed by outputting a 1 at the output when, for example, a 55% limit is exceeded and a 0 when the 45% limit is undershot. The old value is kept in the intermediate area. The real limits of this hysteresis must be adapted to the application, since too narrow limits would otherwise be too sensitive to faults.

Simple mean filter (according to Lothar Miller)

For digital circuits or PLDs, a FIR filter with flip-flops in a row is recommended. You push the input signal into a flip-flop chain and switch above the middle:

SignalInput -> FF1 -> FF2 -> FF3 -> FF4 -> FF5 -> FF6 -> FF7 -> FF8

If all FFs = 1 (sum of FFs = 8) then SignalOutput = 1
If all FFs = 0 (sum of FFs = 0) then SignalOutput = 0

This method can be mapped very simply in logic, because only one NOR or AND gate is required for the calculation of the output.

However, the real signal must be sampled slowly enough so that the filter period exceeds the bounce time to prevent an 8×1 from being seen in the middle of a passive phase of a bounce process. This makes the interation relatively slow.

Comparison of the procedures

  • HW – “debounced switch”: Very expensive, large design, subject to wear, low durability
  • HW – “switch”: requires more complex switches, requires electronics
  • HW – “switch without FF”: requires more complex switches and a small capacitor
  • HW – “capacitor debouncing”: requires a little more space, copes with bad switches
  • SW – edge method:
  • SW – holding pattern: Due to the holding pattern, a not insignificant delay in the code. Especially when several buttons are to be monitored, not unproblematic
  • SW timer: universal functionality that impresses with its low memory consumption, low computing time consumption and good function. At first glance, the ‘consumption’ of a timer looks worse than it is, because most programs use a basic timer for the time control of the program anyway, which can also be used for debouncing the buttons.
  • SW filter: very little space required in FPGAs, relatively good effect
  • SW filter 2: very small space requirement, good effect

Links on the subject

 Posted by at 6:47 pm
Mar 242020



SerialSend is a little command line application I created to send text strings via a serial port. I mainly use it to send information to microcontroller circuits via a USB-to-serial converter, so it’s designed to work well in that context.

  • Copyright © 2010-2019 Ted Burke, All Rights Reserved.

 Posted by at 2:31 pm
Jan 132020

What is VICE?

VICE is a program that runs on a Unix, MS-DOS, Win32, OS/2, BeOS, QNX 4.x, QNX 6.x, Amiga, Syllable or Mac OS X machine and executes programs intended for the old 8-bit computers. The current version emulates the C64, the C64DTV, the C128, the VIC20, practically all PET models, the PLUS4 and the CBM-II (aka C610/C510). An extra emulator is provided for C64 expanded with the CMD SuperCPU.


[NEW] (24 December 2019) Version 3.4 released

  • What is NEW in the latest release? (This is definitely worth reading 🙂
  • VICE has moved its source repository to public services provided by SourceForge. You can find it at We like to thank the SourceForge staff for that help.




The HP Calculator Emulators for the Atari 800XL and for the Commodore 64

In 1972 the great American company Hewlett-Packard shipped their first pocket calculator. It was called HP-35, and it was the first pocket calculator with transcendental functions and the first with the so-called Reverse Polish Notation (RPN). The HP-35 was a huge success with scientific/engineering users, so HP soon came out with a similar model for business users. It was called HP-80, and could solve problems like present and future values of payment streams, trend line calculations (least squares linear regression), ammortization, date calculation, etc. Hewlett-Packard continued with the HP-45, an improved scientific model (which I happen to own :-), and (after the models 65 and 70) with the HP-55, which was programmable and supported a quartz-controlled stopwatch function. These (so-called “classic”) calculators of HP were based upon a proprietary 4-bit CPU developed just for that purpose.I wrote emulators for these four calculators for the Atari 800XL and for the Commodore 64, which simulate the HP calculator CPU to interpret the original program ROMs of the four models. This enables you to work with your Atari 800 or C64 exactly like with the great classic HP calculators with their sophisticated scientific and business functions.

The emulators for the Atari 800XL can be downloaded here:

The emulators for the Commodore 64 can be downloaded here:

You can use these files with an Atari or Commodore emulator or put it on floppy disks and try it on the real machines.

Much more information on HP’s classic (and more modern) calculators can be found at the Museum of HP Calculators.

In the following you find screenshots of the emulators running on the Atari 800XL and on the C64.

Atari 800XL:
Norbert Kehrer's HP Calculator Emulator for the Atari 800XL Norbert Kehrer's HP Calculator Emulator for the Atari 800XL
Norbert Kehrer's HP Calculator Emulator for the Atari 800XL Norbert Kehrer's HP Calculator Emulator for the Atari 800XL
 Posted by at 5:15 pm