Kjetil's Information Center: A Blog About My Projects

Epson HX-20 Emulator Micro-Printer Support

There is now support for the micro-printer in my hex20 Epson HX-20 emulator. The version has been bumped to 0.6 and it can be downloaded here or fetched from the GitHub repository. A text file is specified by the "-p" argument which will get appended with the dot lines from the printer in form of '#' and ' ' characters. The output is 144 dots wide.

The reason this support was added was to experiment with graphical printing on a real HX-20 and having emulation support makes everything a lot easier in terms of software development.

Here is a C program that will generate a dasm compatible assembly program to print a binary PBM image.

#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>

int main(void)
{
  char line[128];
  bool dots[144];
  int c;
  int n;
  int i;
  int dotline;

  fgets(line, sizeof(line), stdin);
  if (line[0] != 'P' && line[1] != '4') {
    fprintf(stderr, "Not a binary PBM image!\n");
    return EXIT_FAILURE;
  }

reread:
  fgets(line, sizeof(line), stdin);
  if (line[0] == '#') {
    goto reread;
  }

  if (strncmp(line, "144 ", 4) != 0) {
    fprintf(stderr, "Width must be 144 pixels!\n");
    return -1;
  }

  /* Generate assembly program header: */
  fprintf(stdout, "        processor hd6303\n");
  fprintf(stdout, "        org $1000\n");
  fprintf(stdout, "        jmp start\n");
  fprintf(stdout, "data\n");

  /* Generate image data: */
  n = 0;
  dotline = 0;
  while ((c = fgetc(stdin)) != EOF) {
    dots[n]   = (c >> 7) & 1;
    dots[n+1] = (c >> 6) & 1;
    dots[n+2] = (c >> 5) & 1;
    dots[n+3] = (c >> 4) & 1;
    dots[n+4] = (c >> 3) & 1;
    dots[n+5] = (c >> 2) & 1;
    dots[n+6] = (c >> 1) & 1;
    dots[n+7] =  c       & 1;
    n += 8;
    if (n == 144) {
      for (i = 0; i < 144; i += 6) {
        fprintf(stdout, "        dc.b $%02x\n",
          ((dots[i+5] << 5) |
           (dots[i+4] << 4) |
           (dots[i+3] << 3) |
           (dots[i+2] << 2) |
           (dots[i+1] << 1) |
           (dots[i])));
      }
      n = 0;
      dotline++;
      if (dotline >= 255) {
        break; /* Limit */
      }
    }
  }

  /* Generate assembly program footer: */
  fprintf(stdout, "start\n");
  fprintf(stdout, "        ldaa #%d\n", dotline);
  fprintf(stdout, "        ldab #24\n");
  fprintf(stdout, "        ldx #data\n");
  fprintf(stdout, "loop\n");
  fprintf(stdout, "        jsr $FF91\n");
  fprintf(stdout, "        abx\n");
  fprintf(stdout, "        deca\n");
  fprintf(stdout, "        bne loop\n");
  fprintf(stdout, "        jmp $FF25\n");

  return EXIT_SUCCESS;
}
          


Here is a Makefile for the entire process, assuming an "image.pbm" input file exists:

all: image.s68

image.bin: image.asm
	dasm $^ -o$@ -f3 -l$(basename $^).lst

image.s68: image.bin
	srec_cat image.bin -binary -offset 0x1000 -o image.s68 -motorola

image.asm: image.pbm hx20ppbm
	./hx20ppbm < image.pbm > image.asm

hx20ppbm: hx20ppbm.c
	gcc -o hx20ppbm hx20ppbm.c -Wall -Wextra

.PHONY: clean
clean:
	rm -f hx20ppbm image.asm *.s68 *.bin *.lst
          


The resulting "image.s68" S-record file can be passed to the MONITOR in the hex20 emulator for testing, where it can be run with the "G1000" command. The hex20 emulator can also be used to write this program to a WAV file which can then be transferred to a real Epson HX-20. A demo video of this can be found here.

Topic: Open Source, by Kjetil @ 01/03-2024, Article Link