Skip to content

Instantly share code, notes, and snippets.

@zeroeth
Created February 7, 2020 09:14
Show Gist options
  • Save zeroeth/c0b83e7a856d01c9db46ee6d414a1654 to your computer and use it in GitHub Desktop.
Save zeroeth/c0b83e7a856d01c9db46ee6d414a1654 to your computer and use it in GitHub Desktop.
cm-5 mode5 revision 5 (newer one in older gists)
/* http://www.housedillon.com/?p=1272
* Written by iskunk (Daniel Richard G.)
* THIS FILE IS IN THE PUBLIC DOMAIN
*
* Program to emulate the CM-5's "random and pleasing" LED panel mode
* (revision 5, "House Dillon video exclusive" edition)
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#define NUM_ROWS 32 /* unique rows */
#define NUM_ROWS_DISPLAYED 106 /* rows in front panel display */
/* Dillon's video shows a single 16x32 panel */
#undef NUM_ROWS_DISPLAYED
#define NUM_ROWS_DISPLAYED 32
#ifndef NDEBUG
# define COMPARE_8741
#endif
#define RNUM_SEED 0xBAD
static uint16_t rnum = RNUM_SEED;
static uint16_t rnum_8741 = RNUM_SEED;
/* 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];
/* The source of this pattern is not [yet] known. Note that all these rows
* will be shifted by one bit before being displayed.
*/
static const uint16_t rows_mystery[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
};
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;
#undef X
rnum = (lfsr_bit << 15) | (rnum >> 1);
return rand_bit;
}
/* This is a rough translation of Jim's Intel 8741 assembler code into C
*/
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 ;light LED only 25 percent of the time */
/* ret ;return */
#undef b
#undef cpl
#undef jnb
#undef orl
#undef rrc
rnum_8741 = RNUM | (RNUMp1 << 8);
return C;
}
static void print_row(uint16_t x)
{
uint16_t m;
int pos;
char v[17];
/* 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 sequence to clear terminal */
fputs("\033[2J\033[1;1H", stdout);
for (i = 0; i < NUM_ROWS_DISPLAYED; i++)
print_row(rows[i & 31]);
}
int main(void)
{
int i;
int t = 2;
/* 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 mystery pattern */
memcpy(rows, rows_mystery, sizeof(rows));
for (;;)
{
for (i = NUM_ROWS - 1; i >= 0; i--)
{
uint16_t bit = get_random_bit();
#ifdef COMPARE_8741
uint16_t bit_8741 = get_random_bit_8741();
assert(bit == bit_8741);
assert(rnum == rnum_8741);
#endif
if (i & 4)
rows[i] = (bit << 15) | (rows[i] >> 1);
else
rows[i] = (rows[i] << 1) | bit;
}
print_panel();
/* Print timestamp for matching to Dillon's video */
if (++t < 300)
printf("\n00:00:%02d:%02d\n", t / 5, 6 * (t % 5));
fflush(stdout);
usleep(200000); /* 200 ms */
}
return 0;
}
/* EOF */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment