Advertisement
iskunk

Attempt at CM-5 "random and pleasing" pattern (rev. 5)

Apr 6th, 2016
887
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 4.81 KB | None | 0 0
  1. /* http://www.housedillon.com/?p=1272
  2.  * Written by iskunk (Daniel Richard G.)
  3.  * THIS FILE IS IN THE PUBLIC DOMAIN
  4.  *
  5.  * Program to emulate the CM-5's "random and pleasing" LED panel mode
  6.  * (revision 5, "House Dillon video exclusive" edition)
  7.  */
  8.  
  9. #include <stdio.h>
  10. #include <stdint.h>
  11. #include <string.h>
  12. #include <unistd.h>
  13. #include <assert.h>
  14.  
  15. #define NUM_ROWS 32     /* unique rows */
  16. #define NUM_ROWS_DISPLAYED 106  /* rows in front panel display */
  17.  
  18. /* Dillon's video shows a single 16x32 panel */
  19. #undef NUM_ROWS_DISPLAYED
  20. #define NUM_ROWS_DISPLAYED 32
  21.  
  22. #ifndef NDEBUG
  23. # define COMPARE_8741
  24. #endif
  25.  
  26. #define RNUM_SEED 0xBAD
  27.  
  28. static uint16_t rnum = RNUM_SEED;
  29. static uint16_t rnum_8741 = RNUM_SEED;
  30.  
  31. /* Note: rows[0] is the top row; most significant bit is at left;
  32.  * a zero bit corresponds to a lit LED
  33.  */
  34. static uint16_t rows[NUM_ROWS];
  35.  
  36. /* The source of this pattern is not [yet] known. Note that all these rows
  37.  * will be shifted by one bit before being displayed.
  38.  */
  39. static const uint16_t rows_mystery[NUM_ROWS] = {
  40.     0x8F10, 0x9112, 0x9314, 0x9516, 0x18E9, 0x5899, 0x38D9, 0x78B9,
  41.     0x9F20, 0xA122, 0xA324, 0xA526, 0x14E5, 0x5495, 0x34D5, 0x74B5,
  42.     0xAF30, 0xB132, 0xB334, 0xB536, 0x1CED, 0x5C9D, 0x3CDD, 0x7CBD,
  43.     0xBF40, 0xC142, 0xC344, 0xC546, 0x12E3, 0x5293, 0x32D3, 0x72B3
  44. };
  45.  
  46. static uint16_t get_random_bit(void)
  47. {
  48. #define X rnum
  49.  
  50.     /* https://en.wikipedia.org/wiki/Linear_feedback_shift_register
  51.      * Primitive polynomial: x^16 + x^15 + x^13 + x^4 + 1
  52.      */
  53.     uint16_t lfsr_bit = ((X >> 0) ^ (X >> 1) ^ (X >> 3) ^ (X >> 12)) & 1;
  54.  
  55.     uint16_t rand_bit = (X | (X >> 2)) & 1;
  56.  
  57. #undef X
  58.  
  59.     rnum = (lfsr_bit << 15) | (rnum >> 1);
  60.  
  61.     return rand_bit;
  62. }
  63.  
  64. /* This is a rough translation of Jim's Intel 8741 assembler code into C
  65.  */
  66. static uint16_t get_random_bit_8741(void)
  67. {
  68.     uint8_t RNUM   = rnum_8741 & 0xFF;  /* low-order byte */
  69.     uint8_t RNUMp1 = rnum_8741 >> 8;    /* high-order byte */
  70.     uint8_t A, C, tmp;
  71.  
  72. #define b(var, n) ((var >> n) & 1)  /* gets Nth bit */
  73. #define cpl(flag) flag = flag ^ 1
  74. #define jnb(val, label) if (!val) goto label
  75. #define orl(flag, val) flag |= val
  76. #define rrc(reg) tmp = reg & 1; reg = (C << 7) | (reg >> 1); C = tmp
  77.  
  78.     /* ;This subroutine implements a 16 bit random number generator based
  79.      * ;on the primitive polynomial:
  80.      * ;
  81.      * ;    1 + X + X^3 + X^12 + X^16
  82.      * ;
  83.      * ;The value is stored in memory as RNUM.  This subroutine returns
  84.      * ;with the low order byte of the RNUM in the accumulator and a random
  85.      * ;bit value in the Carry (C) bit.
  86.      * ;
  87.      */
  88.     C = b(RNUM,0);      /* mov C, RNUM.0    ;get the units value of the PP      */
  89.     jnb(b(RNUM,1), rand1);  /* jnb RNUM.1, rand1    ;jmp if X = 0               */
  90.     cpl(C);         /* cpl C        ;else compliment C (xor)        */
  91. rand1:  jnb(b(RNUM,3), rand2);  /* jnb RNUM.3, rand2    ;jmp if X^3 = 0             */
  92.     cpl(C);         /* cpl C        ;else compliment C (xor)        */
  93. rand2:  jnb(b(RNUMp1,4), rand3);  /* jnb (RNUM+1).4, rand3  ;jmp if X^12 = 0            */
  94.     cpl(C);         /* cpl C        ;else compliment C (xor)        */
  95. rand3:  A = RNUMp1;     /* mov A, RNUM+1    ;get high byte of RNUM          */
  96.     rrc(A);         /* rrc A        ;and rotate down (thru accumulator) */
  97.     RNUMp1 = A;     /* mov RNUM+1, A    ;save it back to memory         */
  98.     A = RNUM;       /* mov A, RNUM      ;get low byte of RNUM           */
  99.     rrc(A);         /* rrc A        ;and rotate down (thru accumulator) */
  100.     RNUM = A;       /* mov RNUM, A      ;save it back to memory         */
  101.     orl(C, b(RNUM,1));  /* orl C, RNUM.1    ;light LED only 25 percent of the time  */
  102.                 /* ret          ;return                 */
  103.  
  104. #undef b
  105. #undef cpl
  106. #undef jnb
  107. #undef orl
  108. #undef rrc
  109.  
  110.     rnum_8741 = RNUM | (RNUMp1 << 8);
  111.  
  112.     return C;
  113. }
  114.  
  115. static void print_row(uint16_t x)
  116. {
  117.     uint16_t m;
  118.     int pos;
  119.     char v[17];
  120.  
  121.     /* 0 -> LED on, 1 -> LED off */
  122.     for (m = 1 << 15, pos = 0; m != 0; m >>= 1, pos++)
  123.         v[pos] = (x & m) ? '-' : 'O';
  124.  
  125.     v[16] = '\0';
  126.  
  127.     puts(v);
  128. }
  129.  
  130. static void print_panel(void)
  131. {
  132.     int i;
  133.  
  134.     /* ANSI sequence to clear terminal */
  135.     fputs("\033[2J\033[1;1H", stdout);
  136.  
  137.     for (i = 0; i < NUM_ROWS_DISPLAYED; i++)
  138.         print_row(rows[i & 31]);
  139. }
  140.  
  141. int main(void)
  142. {
  143.     int i;
  144.     int t = 2;
  145.  
  146.     /* Initial state: all but 3 LEDs lit */
  147.     memset(rows, 0, sizeof(rows));
  148.     rows[0] = 0x9400;
  149.     print_panel();
  150.     fflush(stdout);
  151.     usleep(600000); /* 600 ms */
  152.  
  153.     /* Initialize rows with mystery pattern */
  154.     memcpy(rows, rows_mystery, sizeof(rows));
  155.  
  156.     for (;;)
  157.     {
  158.         for (i = NUM_ROWS - 1; i >= 0; i--)
  159.         {
  160.             uint16_t bit = get_random_bit();
  161.  
  162. #ifdef COMPARE_8741
  163.             uint16_t bit_8741 = get_random_bit_8741();
  164.             assert(bit == bit_8741);
  165.             assert(rnum == rnum_8741);
  166. #endif
  167.  
  168.             if (i & 4)
  169.                 rows[i] = (bit << 15) | (rows[i] >> 1);
  170.             else
  171.                 rows[i] = (rows[i] << 1) | bit;
  172.         }
  173.  
  174.         print_panel();
  175.  
  176.         /* Print timestamp for matching to Dillon's video */
  177.         if (++t < 300)
  178.             printf("\n00:00:%02d:%02d\n", t / 5, 6 * (t % 5));
  179.  
  180.         fflush(stdout);
  181.         usleep(200000); /* 200 ms */
  182.     }
  183.  
  184.     return 0;
  185. }
  186.  
  187. /* EOF */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement