kz80_bc

Crates.iokz80_bc
lib.rskz80_bc
version0.1.0
created_at2025-12-29 01:15:04.155887+00
updated_at2025-12-29 01:15:04.155887+00
descriptionArbitrary-precision decimal arithmetic language and calculator for Z80
homepage
repositoryhttps://github.com/ajokela/kz80_bc
max_upload_size
id2009734
size235,873
Alex Jokela (ajokela)

documentation

README

bc80

An arbitrary-precision decimal calculator and programming language for the Z80 processor. Compiles bc-style programs to native Z80 machine code using BCD (Binary Coded Decimal) arithmetic for exact decimal calculations.

Features

  • Arbitrary Precision: Up to 50 decimal digits of precision
  • bc-Compatible Syntax: Familiar syntax for anyone who has used the Unix bc calculator
  • Native Z80 Code: Compiles directly to Z80 machine code - no interpreter overhead
  • BCD Arithmetic: Exact decimal math with no floating-point rounding errors
  • Interactive REPL: Generate a standalone REPL ROM for interactive calculations
  • Signed Numbers: Full support for negative numbers and signed arithmetic

Supported Operations

Operation Syntax Example
Addition a + b 1 + 2
Subtraction a - b 5 - 3
Multiplication a * b 6 * 7
Division a / b 22 / 7
Parentheses (expr) (1 + 2) * 3
Assignment var = expr x = 42
Comparison <, >, <=, >=, ==, != x > 0

Control Structures

/* If statement */
if (x > 0) {
    x = x - 1
}

/* While loop */
while (n > 0) {
    n = n - 1
}

/* For loop */
for (i = 0; i < 10; i = i + 1) {
    sum = sum + i
}

Functions

/* Define a function */
define factorial(n) {
    if (n <= 1) return 1
    return n * factorial(n - 1)
}

/* Call it */
factorial(10)

Scale (Decimal Precision)

/* Set decimal places for division results */
scale = 10

/* Now division produces 10 decimal places */
1 / 3    /* outputs: .3333333333 */

/* Scale also affects decimal multiplication */
scale = 2
2.5 * 2  /* outputs: 5.0 */

Building

Requires Rust 1.70 or later.

cargo build --release

The binary will be at target/release/bc80.

Usage

Compile a bc Program to Z80 ROM

bc80 program.bc --rom output.bin

Generate Interactive REPL ROM

bc80 --repl calculator.bin

Debug Options

bc80 program.bc --tokens      # Show lexer tokens
bc80 program.bc --ast         # Show parsed AST
bc80 program.bc --bytecode    # Show compiled bytecode

Running on Hardware

The generated ROM images are designed for Z80 systems with:

  • Memory: ROM at 0x0000, RAM at 0x8000+
  • I/O: MC6850 ACIA at ports 0x80/0x81 for serial output

RetroShield Z80

Works with the RetroShield Z80 on Arduino Mega. Use the included emulator for testing:

../emulator/retroshield output.bin

Interactive REPL

The REPL (Read-Eval-Print Loop) provides an interactive calculator experience, similar to the traditional Unix bc command.

Generating the REPL ROM

bc80 --repl calculator.bin

This creates a standalone ~2KB ROM that runs an interactive calculator.

Running the REPL

With the emulator:

../emulator/retroshield calculator.bin

Or load calculator.bin onto your RetroShield Z80 hardware.

REPL Session Example

bc80 REPL v1.0
> 2+3
5
> 10*5
50
> scale=2
2
> 7/2
3.50
> 1.5+2.5
4.0
> 100-250
-150
> (1+2)*(3+4)
21
>

REPL Features

Feature Example Description
Arithmetic 2+3*4 Full operator precedence
Decimals 3.14159 Enter decimal numbers directly
Negative results 5-10 Displays -5
Scale setting scale=5 Set decimal places (echoes the value)
Parentheses (1+2)*3 Group expressions

REPL Limitations

The REPL is a lightweight implementation optimized for the Z80's limited resources:

  • No variables (use the compiled mode for variables)
  • No functions (use the compiled mode for define)
  • No control structures (no if, while, for)
  • Expression length limited by input buffer (~80 characters)
  • Scale maximum of 50 decimal places

For programs requiring variables, functions, or control structures, write a .bc file and compile it with --rom instead.

Examples

Simple Arithmetic

/* simple.bc */
1 + 2
3 * 4
10 - 5

a = 42
a

scale = 10
1 / 3

Factorial

/* factorial.bc */
define f(n) {
    if (n <= 1) return 1
    return n * f(n - 1)
}

f(5)    /* 120 */
f(10)   /* 3628800 */
f(20)   /* 2432902008176640000 */

Calculate Pi (Leibniz Formula)

/* pi.bc */
scale = 50

define pi(n) {
    auto i, s, t
    s = 0
    t = 1
    for (i = 1; i <= n; i += 2) {
        s = s + t / i
        t = -t
    }
    return 4 * s
}

pi(1000)

Architecture

┌─────────────┐     ┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│   Lexer     │────▶│   Parser    │────▶│  Compiler   │────▶│ Z80 Codegen │
│  (lexer.rs) │     │ (parser.rs) │     │(compiler.rs)│     │  (z80.rs)   │
└─────────────┘     └─────────────┘     └─────────────┘     └─────────────┘
     │                    │                   │                    │
     ▼                    ▼                   ▼                    ▼
   Tokens               AST              Bytecode            Z80 ROM

BCD Number Format

Numbers are stored in a 28-byte structure:

Offset Size Description
0 1 Sign (0x00 = positive, 0x80 = negative)
1 1 Length (always 50 digits)
2 1 Scale (decimal places)
3-27 25 Packed BCD digits (2 digits per byte)

Testing

Run the comprehensive math test suite:

bash tests/math_tests.sh

Tests cover:

  • Basic integer operations
  • Addition, subtraction, multiplication, division
  • Negative numbers and signed arithmetic
  • Decimal numbers with scale
  • Order of operations
  • Parentheses
  • Variables
  • Large numbers (up to 50 digits)

Limitations

  • Maximum 50 decimal digits
  • Multiplier limited to 4 digits (0-9999) in current implementation
  • No modulo operator (yet)
  • No exponentiation operator (yet)
  • Single-letter variable names only (a-z)

License

BSD 3-Clause License. See LICENSE for details.

Author

Alex Jokela

See Also

  • RetroShield Z80 - Arduino shield for running Z80 code
  • GNU bc - The original arbitrary precision calculator
Commit count: 0

cargo fmt