Skip to content

Instantly share code, notes, and snippets.

@zeroeth
Created January 17, 2017 06:11
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zeroeth/1f1b1d4cbc1841b48290ff3aa0ad6869 to your computer and use it in GitHub Desktop.
Save zeroeth/1f1b1d4cbc1841b48290ff3aa0ad6869 to your computer and use it in GitHub Desktop.
CM-5 LED code mode 5
/* http://www.housedillon.com/?p=1272
* Written by iskunk (Daniel Richard G.) 2016 April
* printf("<%s@%s.%s>\n", "skunk", "iskunk", "org");
* THIS FILE IS IN THE PUBLIC DOMAIN
*
* Program to emulate a subset of the Thinking Machines Corp. CM-5 front
* LED panel display modes (revision 6)
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#define NUM_ROWS 32 /* unique rows */
#define NUM_ROWS_HALF 16 /* NUM_ROWS divided by 2 */
#define NUM_ROWS_DISPLAYED 106 /* total rows in front panel display */
#define RNUM_SEED 0xBAD /* :-) */
static uint16_t rnum = RNUM_SEED;
static uint16_t rnum_8741 = RNUM_SEED;
/* A Galois LFSR requires a different seed to produce the same output
*/
static uint16_t rnum_galois = 0x917D;
/* Note: rows[0] is the top row; most significant bit is at left;
* a zero bit corresponds to a lit LED
*/
static uint16_t rows[NUM_ROWS];
/* Uninitialized bits, displayed briefly at the start of mode 7
*/
static const uint16_t rows_glitch[NUM_ROWS] = {
0x8F10, 0x9112, 0x9314, 0x9516, 0x18E9, 0x5899, 0x38D9, 0x78B9,
0x9F20, 0xA122, 0xA324, 0xA526, 0x14E5, 0x5495, 0x34D5, 0x74B5,
0xAF30, 0xB132, 0xB334, 0xB536, 0x1CED, 0x5C9D, 0x3CDD, 0x7CBD,
0xBF40, 0xC142, 0xC344, 0xC546, 0x12E3, 0x5293, 0x32D3, 0x72B3
};
/* This is a rough translation of Jim's Intel 8741 assembler code into C.
* His original code and (lightly edited) comments are retained below.
*/
static uint16_t get_random_bit_8741(void)
{
uint8_t RNUM = rnum_8741 & 0xFF; /* low-order byte */
uint8_t RNUMp1 = rnum_8741 >> 8; /* high-order byte */
uint8_t A, C, tmp;
#define b(var, n) ((var >> n) & 1) /* gets Nth bit */
#define cpl(flag) flag = flag ^ 1
#define jnb(val, label) if (!val) goto label
#define orl(flag, val) flag |= val
#define rrc(reg) tmp = reg & 1; reg = (C << 7) | (reg >> 1); C = tmp
/* ;This subroutine implements a 16 bit random number generator based
* ;on the primitive polynomial:
* ;
* ; 1 + X + X^3 + X^12 + X^16
* ;
* ;The value is stored in memory as RNUM. This subroutine returns
* ;with the low order byte of the RNUM in the accumulator and a random
* ;bit value in the Carry (C) bit.
* ;
*/
C = b(RNUM,0); /* mov C, RNUM.0 ;get the units value of the PP */
jnb(b(RNUM,1), rand1); /* jnb RNUM.1, rand1 ;jmp if X = 0 */
cpl(C); /* cpl C ;else compliment C (xor) */
rand1: jnb(b(RNUM,3), rand2); /* jnb RNUM.3, rand2 ;jmp if X^3 = 0 */
cpl(C); /* cpl C ;else compliment C (xor) */
rand2: jnb(b(RNUMp1,4), rand3); /* jnb (RNUM+1).4, rand3 ;jmp if X^12 = 0 */
cpl(C); /* cpl C ;else compliment C (xor) */
rand3: A = RNUMp1; /* mov A, RNUM+1 ;get high byte of RNUM */
rrc(A); /* rrc A ;and rotate down (thru accumulator) */
RNUMp1 = A; /* mov RNUM+1, A ;save it back to memory */
A = RNUM; /* mov A, RNUM ;get low byte of RNUM */
rrc(A); /* rrc A ;and rotate down (thru accumulator) */
RNUM = A; /* mov RNUM, A ;save it back to memory */
orl(C, b(RNUM,1)); /* orl C, RNUM.1 ;set C 75 percent of the time */
/* ret ;return */
#undef b
#undef cpl
#undef jnb
#undef orl
#undef rrc
rnum_8741 = RNUM | (RNUMp1 << 8);
return C;
}
/* "In a software implementation of an LFSR, the Galois form is more
* efficient as the XOR operations can be implemented a word at a
* time: only the output bit must be examined individually."
* -- https://en.wikipedia.org/wiki/Linear_feedback_shift_register
*/
static uint16_t get_random_bit_galois(void)
{
#define X rnum_galois
uint16_t out_bit = X & 1;
uint16_t rand_bit = (X | (X >> 2)) & 1;
X >>= 1;
X ^= (-out_bit) & 0xD008;
#undef X
return rand_bit;
}
static uint16_t get_random_bit(void)
{
#define X rnum
/* https://en.wikipedia.org/wiki/Linear_feedback_shift_register
* Primitive polynomial: x^16 + x^15 + x^13 + x^4 + 1
*/
uint16_t lfsr_bit = ((X >> 0) ^ (X >> 1) ^ (X >> 3) ^ (X >> 12)) & 1;
uint16_t rand_bit = (X | (X >> 2)) & 1;
X = (lfsr_bit << 15) | (X >> 1);
#undef X
#ifndef NDEBUG
/* Compare two alternative implementations of the pseudo-random bit
* generator function */
{
uint16_t rand_bit_8741 = get_random_bit_8741();
uint16_t rand_bit_galois = get_random_bit_galois();
assert(rand_bit == rand_bit_8741);
assert(rand_bit_galois == rand_bit);
assert(rnum == rnum_8741);
}
#endif
return rand_bit;
}
static void print_row(uint16_t x)
{
uint16_t m;
int pos;
char v[17];
/* MSB at left, LSB at right
* 0 -> LED on, 1 -> LED off
*/
for (m = 1 << 15, pos = 0; m != 0; m >>= 1, pos++)
v[pos] = (x & m) ? '-' : 'O';
v[16] = '\0';
puts(v);
}
static void print_panel(void)
{
int i;
/* ANSI escape sequence to clear screen
*/
fputs("\033[2J\033[1;1H", stdout);
for (i = 0; i < NUM_ROWS_DISPLAYED; i++)
print_row(rows[i & 31]);
}
int main(int argc, char **argv)
{
int mode = 7;
int i, j;
int toggle = 0;
if (argc == 2)
{
mode = (int)strtol(argv[1], NULL, 16);
switch (mode)
{
case 5:
case 7:
case 9:
case 0xA:
case 0xB:
break;
default:
printf("error: invalid mode \"%s\"\n", argv[1]);
printf("usage: %s [MODE]\n", argv[0]);
puts("valid options for MODE: 5 7 9 A B");
return 1;
}
}
/* Initial state: all but 3 LEDs lit
*/
memset(rows, 0, sizeof(rows));
rows[0] = 0x9400;
print_panel();
fflush(stdout);
usleep(600000); /* 600 ms */
/* Initialize rows with glitch pattern
*/
memcpy(rows, rows_glitch, sizeof(rows));
for (;;)
{
switch (mode)
{
/* "random and pleasing" */
case 5:
for (i = 0; i < NUM_ROWS_HALF; i++)
{
for (j = 0; j < 16; j++)
{
/* Note that the upper half of the
* panel is one JTAG chain, and the
* lower half is another */
uint16_t bit_lower = get_random_bit();
uint16_t bit_upper = get_random_bit();
rows[i] <<= 1;
rows[i] |= bit_upper;
rows[i + NUM_ROWS_HALF] <<= 1;
rows[i + NUM_ROWS_HALF] |= bit_lower;
}
}
break;
/* "interleaved display of random and pleasing" */
case 7:
for (i = NUM_ROWS - 1; i >= 0; i--)
{
uint16_t bit = get_random_bit();
if (i & 4)
rows[i] = (bit << 15) | (rows[i] >> 1);
else
rows[i] = (rows[i] << 1) | bit;
}
break;
/* "all leds on" */
case 9:
memset(rows, 0, sizeof(rows));
break;
/* "all leds off" */
case 0xA:
memset(rows, 0xFF, sizeof(rows));
break;
/* "continuous blink leds on then off" */
case 0xB:
memset(rows, toggle ? 0 : 0xFF, sizeof(rows));
toggle ^= 1;
break;
}
print_panel();
fflush(stdout);
usleep(200000); /* 200 ms */
}
return 0;
}
/* EOF */
0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment