├── Makefile ├── .gitattributes ├── gpio.h ├── .gitignore ├── install_deeper.sh ├── deeper.init ├── README.md ├── gpio.c └── deeper.c /Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS=-std=c99 -U__STRICT_ANSI__ -Wno-unused-result -D_GNU_SOURCE -DUSE_READER_THREAD -DHAVE_DLOPEN=so -I . -I PDP8 3 | DEPS = gpio.h 4 | OBJ = deeper.o gpio.o 5 | LIBS = -lm -lrt -lpthread -ldl 6 | 7 | 8 | %.o: %.c $(DEPS) 9 | $(CC) -c -o $@ $< $(CFLAGS) 10 | 11 | deeper: $(OBJ) 12 | $(CC) -o $@ $^ $(CFLAGS) $(LIBS) 13 | 14 | clean: 15 | rm -f *.o 16 | 17 | 18 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /gpio.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include // extra 9 | 10 | 11 | //#define BCM2708_PERI_BASE 0x3f000000 12 | //#define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) // GPIO controller 13 | 14 | #define BLOCK_SIZE (4*1024) 15 | 16 | // IO Acces 17 | struct bcm2835_peripheral { 18 | unsigned long addr_p; 19 | int mem_fd; 20 | void *map; 21 | volatile unsigned int *addr; 22 | }; 23 | 24 | //struct bcm2835_peripheral gpio = {GPIO_BASE}; 25 | 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | -------------------------------------------------------------------------------- /install_deeper.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "Deeper Thought 2 Install Script\n" 4 | 5 | # Make sure user is root 6 | if [ "$(id -u)" != "0" ]; then 7 | echo "Access denied: Must be root" 8 | exit 1 9 | fi 10 | 11 | is_running() { 12 | testrun=$(ps -ef | grep "/usr/bin/deeper" | grep -v "grep" | grep -v "SCREEN" | wc -l) 13 | if [ $testrun -eq "0" ]; 14 | then 15 | return 1 16 | else 17 | return 0 18 | fi 19 | } 20 | 21 | if (is_running); then 22 | /etc/init.d/deeper stop 23 | sleep 2 24 | fi 25 | 26 | make 27 | cp deeper /usr/bin/ 28 | cp deeper.init /etc/init.d/deeper 29 | 30 | case "$1" in 31 | "--no-autostart") 32 | echo "Deeper Thought auto-start was not changed." 33 | echo "PiDP-8 simulator auto-start was not changed." 34 | ;; 35 | "--restore-pidp8") 36 | echo "Disabling auto-start for Deeper Thought..." 37 | update-rc.d deeper remove 38 | echo "Enabling auto-start for PiDP-8 simulator..." 39 | update-rc.d pidp8 defaults 40 | ;; 41 | *) 42 | echo "Disabling auto-start for PiDP-8 simulator..." 43 | update-rc.d pidp8 remove 44 | echo "Enabling auto-start for Deeper Thought..." 45 | update-rc.d deeper defaults 46 | ;; 47 | esac 48 | 49 | echo "\nTo run Deeper Thought as a daemon in the background:" 50 | /etc/init.d/deeper help 51 | 52 | echo "\nTo run Deeper Thought in the shell window and see its output run:" 53 | echo " sudo /usr/bin/deeper" 54 | 55 | -------------------------------------------------------------------------------- /deeper.init: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ### BEGIN INIT INFO 3 | # Provides: deeper 4 | # Required-Start: $remote_fs $syslog 5 | # Required-Stop: $remote_fs $syslog 6 | # Default-Start: 2 3 4 5 7 | # Default-Stop: 0 1 6 8 | # Short-Description: Start Deeper Thought at boot time 9 | # Description: Start Deeper Thought at boot time 10 | ### END INIT INFO 11 | 12 | # Make sure user is root 13 | if [ "$(id -u)" != "0" ]; then 14 | echo "Access denied: Must be root" 15 | exit 1 16 | fi 17 | 18 | is_running() { 19 | testrun=$(ps -ef | grep "/usr/bin/deeper" | grep -v "grep" | grep -v "SCREEN" | wc -l) 20 | if [ $testrun -eq "0" ]; 21 | then 22 | return 1 23 | else 24 | return 0 25 | fi 26 | } 27 | 28 | start() { 29 | if (is_running); then 30 | echo "Deeper Thought is already running" 31 | return 1 32 | else 33 | echo "Starting Deeper Thought" 34 | screen -dmS deeper /usr/bin/deeper 35 | return 0 36 | fi 37 | } 38 | 39 | stop() { 40 | if (is_running); then 41 | echo "Stopping Deeper Thought" 42 | kill -2 $(pidof deeper) 43 | return 0 44 | else 45 | echo "Deeper Thought is already stopped" 46 | return 1 47 | fi 48 | 49 | } 50 | 51 | status() { 52 | if (is_running); 53 | then 54 | echo "Deeper Thought is Running" 55 | else 56 | echo "Deeper Thought is stopped" 57 | fi 58 | } 59 | 60 | case "$1" in 61 | start) 62 | start 63 | ;; 64 | stop) 65 | stop 66 | ;; 67 | restart) 68 | stop 69 | start 70 | ;; 71 | status) 72 | status 73 | ;; 74 | *) 75 | echo "Usage: sudo /etc/init.d/deeper {start|stop|restart|status}" 76 | exit 1 77 | ;; 78 | esac 79 | 80 | exit 0 81 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #Deeper Thought 2 2 | A program that blinks the LEDs on the [PiDP-8 kit](http://obsolescence.wix.com/obsolescence#!pidp-8/cbie) created by Oscar Vermeulen. This program is C++ and does not run in the PDP-8 simulator. The default mode is designed to be similar to Steve Gibson's Deep Thought program for the PDP-8. 3 | 4 | Deeper Thought 2 is a fork of [Deeper Thought by Norman Davie](https://groups.google.com/d/msg/pidp-8/tbciVNoZJbw/AMjywRKLAwAJ). The file gpio.c and gpio.h were copied from Oscar Vermeulen's PDP-8/simH project. 5 | 6 | **[Deeper Thought 2 Demo Video on YouTube](https://youtu.be/0OudB99Cccc)** 7 | 8 | #####Added modes by changing the 3 far left brown switches (0=down / 1=up) 9 | * **111** = Normal mode with all LEDs flashing (Default / Undefined fallback) 10 | * **011** = Sleep Mode (All LEDs off except for the columns on the right side of the panel) 11 | * **101** = Dim Mode - Fewer LEDs Blink (Only the Program Counter, Memory Address and Memory Buffer groups) 12 | * **110** = Binary Clock (From top to bottom: Hour, Minute, Second, Month, Day) 13 | * **001** = Snake Mode (3 LEDs move across a row then down to the next row in the opposite direction) 14 | * **000** = Test Mode (All LEDs on steady, except some of the columns of LEDs on the right blink off for 20ms) 15 | * **010** = Pong Mode / Bouncing ball - by Norman Davie 16 | * **100** = Text scroller 17 | 18 | #####Expanded the timing switches from 6 to 12 switches 19 | * The third brown and third white switch groups from the left control the maximum delay (slowest speed) 20 | * Up = More delay (slower) 21 | * Down = Less delay (faster) 22 | * The value from the switches is multiplied by 50,000us (50ms). 23 | * The second brown and second white switch groups from the left control the variability of the timing 24 | * Up = More variability 25 | * Down = Less variability (all down results in steady timing) 26 | * The varied amount is subtracted from the max delay, making the LEDs change faster. 27 | * The timing range should be the similar to version 1.0, but with more degrees of change 28 | * The maximum delay switch mask value has 1 added to it to prevent a delay of 0, which crashed the program. 29 | * The delay range (before variability) is 50ms to 3200ms 30 | 31 | #####Changed the behavior of the LED columns on the right side of the panel 32 | * All LEDs in the left column blink randomly. 33 | * Some of these LEDs are programmed to flash more often than others (see the rand_flag function). 34 | * The left column of LEDs are turned off for 20ms at the end of each cycle. 35 | * This gives the left column a short blink even if that LED stays on in the next cycle. 36 | * The 20ms delay is subtracted from the main blink delay to keep the same timing. 37 | * Instead of toggling the execute LED, it blinks for 20ms. 38 | * It is turned on at the beginning of the cycle and turned off before the 20ms delay described above. 39 | 40 | #####Changed the stop switch so that it must be held for 3 seconds to quit the program 41 | 42 | #####Added new command sequences: 43 | * Shutdown system - Flip both the Sing Inst and Sing Step switches down and hold the Stop button for 3 seconds 44 | * Reboot system - Flip both the Sing Inst and Sing Step switches down and hold the Start button for 3 seconds 45 | 46 | #####Misc Notes: 47 | * Added console output that shows switch values when the switches change. 48 | * The blink delay is fixed to 1/2 second in Binary Clock mode. 49 | * This should not be run simultaneously with the pidp8 simulator 50 | 51 | #####Installation 52 | * To install run "sudo ./install_deeper.sh" in the deeper directory (also builds) 53 | * The install script enables auto-start and disables auto-start for the pidp8 simulator 54 | * To install without enabling auto-start, add the "--no-autostart" parameter 55 | * To later disable auto-start and restore the pidp8 simulator auto-start, add the "--restore-pidp8" parameter 56 | * To just build run "make" in the deeper directory. 57 | 58 | #####Running Deeper Thought 2 (if installed with the install script) 59 | * Stop the pidp8 simulator before running this (sudo /etc/init.d/pidp8 stop) 60 | * To run as a daemon in the background: 61 | * sudo /etc/init.d/deeper {start|stop|restart|status} 62 | * To run in the terminal window run: 63 | * sudo /usr/bin/deeper 64 | -------------------------------------------------------------------------------- /gpio.c: -------------------------------------------------------------------------------- 1 | /* 2 | * gpio.c: the real-time process that handles multiplexing 3 | * 4 | * www.obsolescenceguaranteed.blogspot.com 5 | * 6 | * The only communication with the main program (simh): 7 | * - external variable ledstatus is read to determine which leds to light. 8 | * - external variable switchstatus is updated with current switch settings. 9 | * 10 | */ 11 | 12 | 13 | // TO DO: define SERIALSETUP to use PiDPs wired for serial port 14 | //#define SERIALSETUP 15 | 16 | 17 | #include 18 | #include 19 | #include 20 | #include "gpio.h" 21 | 22 | typedef unsigned int uint32; 23 | typedef signed int int32; 24 | typedef unsigned short uint16; 25 | 26 | void short_wait(void); // used as pause between clocked GPIO changes 27 | unsigned bcm_host_get_peripheral_address(void); // find Pi 2 or Pi's gpio base address 28 | static unsigned get_dt_ranges(const char *filename, unsigned offset); // Pi 2 detect 29 | 30 | struct bcm2835_peripheral gpio; // needs initialisation 31 | 32 | long intervl = 300000; // light each row of leds this long 33 | 34 | uint32 switchstatus[3] = { 0 }; // bitfields: 3 rows of up to 12 switches 35 | uint32 ledstatus[8] = { 0 }; // bitfields: 8 ledrows of up to 12 LEDs 36 | 37 | // PART 1 - GPIO and RT process stuff ---------------------------------- 38 | 39 | // GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) 40 | #define INP_GPIO(g) *(gpio.addr + ((g)/10)) &= ~(7<<(((g)%10)*3)) 41 | #define OUT_GPIO(g) *(gpio.addr + ((g)/10)) |= (1<<(((g)%10)*3)) 42 | #define SET_GPIO_ALT(g,a) *(gpio.addr + (((g)/10))) |= (((a)<=3?(a) + 4:(a)==4?3:2)<<(((g)%10)*3)) 43 | 44 | #define GPIO_SET *(gpio.addr + 7) // sets bits which are 1 ignores bits which are 0 45 | #define GPIO_CLR *(gpio.addr + 10) // clears bits which are 1 ignores bits which are 0 46 | 47 | #define GPIO_READ(g) *(gpio.addr + 13) &= (1<<(g)) 48 | 49 | #define GPIO_PULL *(gpio.addr + 37) // pull up/pull down 50 | #define GPIO_PULLCLK0 *(gpio.addr + 38) // pull up/pull down clock 51 | 52 | 53 | // Exposes the physical address defined in the passed structure using mmap on /dev/mem 54 | int map_peripheral(struct bcm2835_peripheral *p) 55 | { 56 | if ((p->mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) { 57 | printf("Failed to open /dev/mem, try checking permissions.\n"); 58 | return -1; 59 | } 60 | p->map = mmap( 61 | NULL, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, 62 | p->mem_fd, // File descriptor to physical memory virtual file '/dev/mem' 63 | p->addr_p); // Address in physical map that we want this memory block to expose 64 | if (p->map == MAP_FAILED) { 65 | perror("mmap"); 66 | return -1; 67 | } 68 | p->addr = (volatile unsigned int *)p->map; 69 | return 0; 70 | } 71 | 72 | void unmap_peripheral(struct bcm2835_peripheral *p) 73 | { munmap(p->map, BLOCK_SIZE); 74 | close(p->mem_fd); 75 | } 76 | 77 | 78 | // PART 2 - the multiplexing logic driving the front panel ------------- 79 | 80 | uint8_t ledrows[] = {20, 21, 22, 23, 24, 25, 26, 27}; 81 | uint8_t rows[] = {16, 17, 18}; 82 | 83 | #ifdef SERIALSETUP 84 | uint8_t cols[] = {13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2}; 85 | #else 86 | uint8_t cols[] = {13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 15, 14}; 87 | #endif 88 | 89 | 90 | void *blink(int *terminate) 91 | { 92 | int i,j,k,switchscan, tmp; 93 | 94 | // Find gpio address (different for Pi 2) ---------- 95 | gpio.addr_p = bcm_host_get_peripheral_address() + + 0x200000; 96 | if (gpio.addr_p== 0x20200000) printf("RPi Plus detected\n"); 97 | else printf("RPi 2 detected\n"); 98 | 99 | // set thread to real time priority ----------------- 100 | struct sched_param sp; 101 | sp.sched_priority = 98; // maybe 99, 32, 31? 102 | if (pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp)) 103 | { fprintf(stderr, "warning: failed to set RT priority\n"); } 104 | // -------------------------------------------------- 105 | if(map_peripheral(&gpio) == -1) 106 | { printf("Failed to map the physical GPIO registers into the virtual memory space.\n"); 107 | return (void *)-1; 108 | } 109 | 110 | // initialise GPIO (all pins used as inputs, with pull-ups enabled on cols) 111 | // INSERT CODE HERE TO SET GPIO 14 AND 15 TO I/O INSTEAD OF ALT 0. 112 | // AT THE MOMENT, USE "sudo ./gpio mode 14 in" and "sudo ./gpio mode 15 in". "sudo ./gpio readall" to verify. 113 | 114 | for (i=0;i<8;i++) // Define ledrows as input 115 | { INP_GPIO(ledrows[i]); 116 | GPIO_CLR = 1 << ledrows[i]; // so go to Low when switched to output 117 | } 118 | for (i=0;i<12;i++) // Define cols as input 119 | { INP_GPIO(cols[i]); 120 | } 121 | for (i=0;i<3;i++) // Define rows as input 122 | { INP_GPIO(rows[i]); 123 | } 124 | 125 | // BCM2835 ARM Peripherals PDF p 101 & elinux.org/RPi_Low-level_peripherals#Internal_Pull-Ups_.26_Pull-Downs 126 | GPIO_PULL = 2; // pull-up 127 | short_wait(); // must wait 150 cycles 128 | #ifdef SERIALSETUP 129 | GPIO_PULLCLK0 = 0x03ffc; // selects GPIO pins 2..13 (frees up serial port on 14 & 15) 130 | #else 131 | GPIO_PULLCLK0 = 0x0fff0; // selects GPIO pins 4..15 (assumes we avoid pins 2 and 3!) 132 | #endif 133 | short_wait(); 134 | GPIO_PULL = 0; // reset GPPUD register 135 | short_wait(); 136 | GPIO_PULLCLK0 = 0; // remove clock 137 | short_wait(); // probably unnecessary 138 | 139 | // BCM2835 ARM Peripherals PDF p 101 & elinux.org/RPi_Low-level_peripherals#Internal_Pull-Ups_.26_Pull-Downs 140 | GPIO_PULL = 0; // no pull-up no pull-down just float 141 | short_wait(); // must wait 150 cycles 142 | GPIO_PULLCLK0 = 0x0ff00000; // selects GPIO pins 20..27 143 | short_wait(); 144 | GPIO_PULL = 0; // reset GPPUD register 145 | short_wait(); 146 | GPIO_PULLCLK0 = 0; // remove clock 147 | short_wait(); // probably unnecessary 148 | 149 | // BCM2835 ARM Peripherals PDF p 101 & elinux.org/RPi_Low-level_peripherals#Internal_Pull-Ups_.26_Pull-Downs 150 | GPIO_PULL = 0; // no pull-up no pull down just float 151 | // not the reason for flashes it seems: 152 | //GPIO_PULL = 2; // pull-up - letf in but does not the reason for flashes 153 | short_wait(); // must wait 150 cycles 154 | GPIO_PULLCLK0 = 0x070000; // selects GPIO pins 16..18 155 | short_wait(); 156 | GPIO_PULL = 0; // reset GPPUD register 157 | short_wait(); 158 | GPIO_PULLCLK0 = 0; // remove clock 159 | short_wait(); // probably unnecessary 160 | // -------------------------------------------------- 161 | 162 | //printf("\nFP on\n"); 163 | 164 | while(*terminate==0) 165 | { 166 | // prepare for lighting LEDs by setting col pins to output 167 | for (i=0;i<12;i++) 168 | { INP_GPIO(cols[i]); // 169 | OUT_GPIO(cols[i]); // Define cols as output 170 | } 171 | 172 | // light up 8 rows of 12 LEDs each 173 | for (i=0;i<8;i++) 174 | { 175 | 176 | // Toggle columns for this ledrow (which LEDs should be on (CLR = on)) 177 | for (k=0;k<12;k++) 178 | { if ((ledstatus[i]&(1< 157 | #include 158 | #include 159 | #include 160 | #include 161 | #include 162 | #include 163 | #include 164 | 165 | typedef unsigned int uint32; 166 | typedef signed int int32; 167 | typedef unsigned short uint16; 168 | typedef unsigned char uint8; 169 | 170 | extern void *blink(void *ptr); // the real-time multiplexing process to start up 171 | extern uint32 ledstatus[8]; // bitfields: 8 ledrows of up to 12 LEDs 172 | extern uint32 switchstatus[3]; // bitfields: 3 rows of up to 12 switches 173 | 174 | 175 | #include 176 | #include 177 | 178 | // GET / STORE row shift mask value 179 | int programCounter[] = {0x00, 0, 07777}; 180 | int dataField[] = {0x07, 9, 07}; 181 | int instField[] = {0x07, 6, 07}; 182 | int linkLED[] = {0x07, 5, 01}; 183 | int memoryAddress[] = {0x01, 0, 07777}; 184 | int memoryBuffer[] = {0x02, 0, 07777}; 185 | int accumulator[] = {0x03, 0, 07777}; 186 | int multiplierQuotient[]= {0x04, 0, 07777}; 187 | int andLED[] = {0x05, 11, 01}; 188 | int tadLED[] = {0x05, 10, 01}; 189 | int iszLED[] = {0x05, 9, 01}; 190 | int dcaLED[] = {0x05, 8, 01}; 191 | int jmsLED[] = {0x05, 7, 01}; 192 | int iotLED[] = {0x05, 5, 01}; 193 | int jmpLED[] = {0x05, 6, 01}; 194 | int oprLED[] = {0x05, 4, 01}; 195 | int fetchLED[] = {0x05, 3, 01}; 196 | int executeLED[] = {0x05, 2, 01}; 197 | int deferLED[] = {0x05, 1, 01}; 198 | int wordCountLED[] = {0x05, 0, 01}; 199 | int currentAddressLED[] = {0x06, 11, 01}; 200 | int breakLED[] = {0x06, 10, 01}; 201 | int ionLED[] = {0x06, 9, 01}; 202 | int pauseLED[] = {0x06, 8, 01}; 203 | int runLED[] = {0x06, 7, 01}; 204 | int stepCounter[] = {0x06, 0, 0177}; 205 | 206 | // GETSWOTCJ 207 | int singInst[] = {0x02, 4, 01}; 208 | int singStep[] = {0x02, 5, 01}; 209 | int stop[] = {0x02, 6, 01}; 210 | int cont[] = {0x02, 7, 01}; 211 | int exam[] = {0x02, 8, 01}; 212 | int dep[] = {0x02, 9, 01}; 213 | int loadAdd[] = {0x02, 10, 01}; 214 | int start[] = {0x02, 11, 01}; 215 | 216 | // GETSWITCHES 217 | int swregister[] = {0x00, 0, 07777}; 218 | int step[] = {0x01, 6, 077}; 219 | 220 | // STORE 221 | // 1) clamps the maximum value via an and mask 222 | // 2) shifts the value to the appropriate area of within the uint 223 | // 3) masks out the value that was previously there without effecting other bits 224 | // 4) or's the new value in place 225 | #define STORE(item, value) { ledstatus[item[0]] = (ledstatus[item[0]] & ~(item[2] << item[1]) ) | ((value & item[2]) << item[1]); } 226 | 227 | // GET 228 | // 1) gets shifts the value to the "normal" range 229 | // 2) masks off bits that are not related to our value 230 | #define GET(item) ( (ledstatus [ item[0] ] >> item[1]) & item[2] ) 231 | #define GETSWITCH(flip) !( (switchstatus [ flip[0] ] >> flip[1]) & flip[2] ) 232 | #define GETSWITCHES(flip) ( (switchstatus [ flip[0] ] >> flip[1]) & flip[2] ) 233 | 234 | 235 | int terminate=0; 236 | 237 | int opled_delay = 20000; 238 | 239 | 240 | // Handle CTRL-C 241 | void sig_handler( int signo ) 242 | { 243 | if( signo == SIGINT ) 244 | terminate = 1; 245 | } 246 | 247 | // Random flag value with a fixed probability 248 | // Creates a random number between 1 and max_rand 249 | // If the random number is <= max_true, TRUE is returned 250 | // Example: rand_flag(100, 60) should give you: 251 | // 60% probability true / 40% probability false 252 | int rand_flag( int max_rand, int max_true ) 253 | { 254 | int rand_value; 255 | rand_value = (rand() % max_rand) + 1; 256 | if(rand_value <= max_true) 257 | { 258 | return 1; 259 | } 260 | else 261 | { 262 | return 0; 263 | } 264 | } 265 | 266 | void ClearAllLEDs() // function added by Norman Davie - used by Pong mode 267 | { 268 | STORE(programCounter, 0); 269 | STORE(dataField, 0); 270 | STORE(instField, 0); 271 | STORE(linkLED, 0); 272 | STORE(programCounter, 0); 273 | STORE(memoryAddress, 0); 274 | STORE(memoryBuffer, 0); 275 | STORE(accumulator, 0); 276 | STORE(multiplierQuotient,0); 277 | STORE(stepCounter, 0); 278 | STORE(andLED, 0); 279 | STORE(tadLED, 0); 280 | STORE(iszLED, 0); 281 | STORE(dcaLED, 0); 282 | STORE(jmsLED, 0); 283 | STORE(iotLED, 0); 284 | STORE(jmpLED, 0); 285 | STORE(oprLED, 0); 286 | STORE(fetchLED, 0); 287 | STORE(executeLED, 0); 288 | STORE(deferLED, 0); 289 | STORE(wordCountLED, 0); 290 | STORE(currentAddressLED, 0); 291 | STORE(breakLED, 0); 292 | STORE(ionLED, 0); 293 | STORE(pauseLED, 0); 294 | STORE(runLED, 0); 295 | } 296 | 297 | void loadMsg(char *tmpMsg) { 298 | char my_line[256]; 299 | char *my_fname = "/home/pdp/scrollText.txt"; 300 | FILE *my_file; 301 | my_file = fopen(my_fname, "r"); 302 | time_t t = time(NULL); 303 | 304 | strcpy(tmpMsg, ""); 305 | 306 | if (my_file == NULL) { 307 | strcat(tmpMsg, "WELCOME TO THE PiDP-8/I TEXT SCROLLER BY DAVID C. EILERING. "); 308 | strcat(tmpMsg, "TO CUSTOMIZE THIS MESSAGE, ENTER THE DESIRED TEXT INTO THE FILE "); 309 | strcat(tmpMsg, my_fname); 310 | strcat(tmpMsg, " "); 311 | strcat(tmpMsg, "FOR MORE INFORMATION, VISIT https://github.com/VentureKing/Deeper-Thought-2 "); 312 | strcat(tmpMsg, "THE CURRENT DATE/TIME IS: "); 313 | strcat(tmpMsg, asctime(localtime(&t))); 314 | strcat(tmpMsg, " "); 315 | } 316 | else { 317 | while (fgets(my_line, sizeof(my_line), my_file)) { 318 | // replace carriage return with null 319 | for (int i = 255; i > 0; i--) { 320 | if (my_line[i] == 0x0A) { 321 | my_line[i] = 0x00; 322 | } 323 | } 324 | 325 | strcat(tmpMsg, my_line); 326 | } 327 | fclose(my_file); 328 | } 329 | } 330 | 331 | 332 | int main( int argc, char *argv[] ) 333 | { 334 | pthread_t thread1; 335 | int iret1; 336 | unsigned long sleepTime; 337 | int deeperThoughtMode = 0; 338 | int dontChangeLEDs = 0; 339 | unsigned long delayAmount; 340 | unsigned long varietyAmount; 341 | unsigned long varietyMult; 342 | unsigned long swRegValue; 343 | unsigned long swStepValue; 344 | unsigned long stopPressedTime; 345 | unsigned long startPressedTime; 346 | int swIfValue; 347 | time_t currentTime; 348 | struct tm *localTime; 349 | int hour; 350 | int min; 351 | int sec; 352 | int x, y, shift_dir; 353 | 354 | x = 1; 355 | y = 1; 356 | shift_dir = 1; 357 | 358 | swRegValue = 0; 359 | swStepValue = 0; 360 | 361 | 362 | char chars[] = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; 363 | 364 | int letters[95] = { 365 | 0x00000003, 0x000000B9, 0x0000601B, 0x057D5F55, 0x04D7F595, 366 | 0x0888888D, 0x08225555, 0x00000019, 0x00001172, 0x00000E8A, 367 | 0x0513E455, 0x00008E23, 0x00000882, 0x00008423, 0x00000081, 368 | 0x00888885, 0x074EB975, 0x0847F285, 0x0956B5CD, 0x0556B58D, 369 | 0x0F90843D, 0x04D6B59D, 0x04D6B575, 0x0187A10D, 0x0556B555, 370 | 0x0756B515, 0x00000051, 0x00000A82, 0x00022A23, 0x00014A53, 371 | 0x00008A8B, 0x0106A105, 0x0726B175, 0x0F14A5F5, 0x0556B5FD, 372 | 0x08C63175, 0x074631FD, 0x08D6B5FD, 0x0094A5FD, 0x0ED6B175, 373 | 0x0F9084FD, 0x00023F8B, 0x07C63145, 0x08A884FD, 0x084210FD, 374 | 0x0F8882FD, 0x0FA082FD, 0x07463175, 0x0114A5FD, 0x087A3175, 375 | 0x0D14A5FD, 0x04D6B595, 0x0087E10D, 0x07C2107D, 0x03A2083D, 376 | 0x0FA088FD, 0x08A88A8D, 0x008B820D, 0x08CEB98D, 0x000011FA, 377 | 0x0820820D, 0x00001F8A, 0x00004113, 0x08421085, 0x0000020A, 378 | 0x0F56B54D, 0x064A52FD, 0x05463175, 0x0FCA5265, 0x0B56B575, 379 | 0x0084A5F5, 0x0756B595, 0x0C1084FD, 0x000000E9, 0x00361044, 380 | 0x08A884FD, 0x0002107B, 0x0F07C1F5, 0x0F0421FD, 0x07463175, 381 | 0x032529FD, 0x0FA52935, 0x010422FD, 0x04D6B595, 0x0442527D, 382 | 0x0FA2107D, 0x01B20C1D, 0x07C1F07D, 0x08A88A8D, 0x07D2949D, 383 | 0x08CEB98D, 0x00001B22, 0x000000F9, 0x000004DA, 0x01104115 384 | }; 385 | 386 | char msg[2048] = ""; 387 | 388 | int msgLen; 389 | int charNum; 390 | int charWidth; 391 | int currChar; 392 | int bank1 = 0; 393 | int bank2 = 0; 394 | int bank3 = 0; 395 | int bank4 = 0; 396 | int bank5 = 0; 397 | int bankMask = 0xFFF; 398 | int letterGap = 1; 399 | int msgPos = 0; 400 | int charPos = 0; 401 | 402 | // install handler to terminate future thread 403 | if( signal(SIGINT, sig_handler) == SIG_ERR ) 404 | { 405 | fprintf( stderr, "Failed to install SIGINT handler.\n" ); 406 | exit( EXIT_FAILURE ); 407 | } 408 | 409 | // create thread 410 | iret1 = pthread_create( &thread1, NULL, blink, &terminate ); 411 | 412 | if( iret1 ) 413 | { 414 | fprintf( stderr, "Error creating thread, return code %d\n", iret1 ); 415 | exit( EXIT_FAILURE ); 416 | } 417 | 418 | sleep( 2 ); // allow 2 sec for multiplex to start 419 | 420 | srand(time(NULL)); 421 | 422 | // set the status LEDs 423 | STORE(ionLED, 1); 424 | STORE(fetchLED, 1); 425 | STORE(executeLED, 1); 426 | STORE(runLED, 1); 427 | STORE(pauseLED, 0); 428 | STORE(jmpLED, 1); 429 | 430 | while(! terminate) 431 | { 432 | // blink the execute LED after every randomization 433 | //STORE(executeLED, ! GET(executeLED)); 434 | STORE(executeLED, 1); 435 | 436 | // Use DF switches to control mode 437 | deeperThoughtMode = (GETSWITCHES(step) & 070)>>3; 438 | 439 | // Get IF switches value 440 | swIfValue = (GETSWITCHES(step) & 07); 441 | 442 | // if we're paused -- don't change the LEDs 443 | if (! dontChangeLEDs) 444 | { 445 | // Maximum amount to delay between changes 446 | // least signifiant address lines control the maximum delay 447 | // all "up" -- maximum delay 448 | // all "down" -- minimal delay 449 | //delayAmount = (GETSWITCHES(swregister) & 07) * 400000L; 450 | delayAmount = ((GETSWITCHES(swregister) & 077)+1) * 50000L; 451 | 452 | // How much to vary the above timing 453 | // the next bank of three address lines control how much 454 | // we can shorten the maximum delay 455 | // all "up" -- we can shorten to zero seconds 456 | // all "down" -- must use maximum time before we change 457 | //varietyMult = (GETSWITCHES(swregister) & 070)>>3; 458 | varietyMult = (GETSWITCHES(swregister) & 07700)>>6; 459 | //varietyAmount = (unsigned long) (((rand() & delayAmount) / 7.0f) * varietyMult); 460 | varietyAmount = (unsigned long) (((rand() % delayAmount) / 63.0f) * varietyMult); 461 | 462 | sleepTime = delayAmount - varietyAmount; 463 | 464 | // In future revisions, we'll have different randomization sequences 465 | switch(deeperThoughtMode) 466 | { 467 | case 3: // 011 = Most LEDs Off 468 | STORE(programCounter, 0); 469 | STORE(memoryAddress, 0); 470 | STORE(memoryBuffer, 0); 471 | STORE(accumulator, 0); 472 | STORE(multiplierQuotient,0); 473 | STORE(stepCounter, 0); 474 | STORE(dataField, 0); 475 | STORE(instField, 0); 476 | // Randomly blink first column of operation LEDs 477 | STORE(andLED, rand_flag(100,20)); 478 | STORE(tadLED, rand_flag(100,2)); 479 | STORE(iszLED, rand_flag(100,5)); 480 | STORE(dcaLED, rand_flag(100,5)); 481 | STORE(jmsLED, rand_flag(100,5)); 482 | STORE(jmpLED, rand_flag(100,15)); 483 | STORE(iotLED, rand_flag(100,10)); 484 | STORE(oprLED, rand_flag(100,10)); 485 | STORE(linkLED, 0); 486 | STORE(deferLED, 0); 487 | STORE(wordCountLED, 0); 488 | STORE(currentAddressLED, 0); 489 | STORE(breakLED, 0); 490 | STORE(ionLED, 0); 491 | STORE(fetchLED, 0); 492 | break; 493 | case 0: // 000 = ALL LEDS ON 494 | STORE(programCounter, 65535 & programCounter[2]); 495 | STORE(memoryAddress, 65535 & memoryAddress[2]); 496 | STORE(memoryBuffer, 65535 & memoryBuffer[2]); 497 | STORE(accumulator, 65535 & accumulator[2]); 498 | STORE(multiplierQuotient,65535 & multiplierQuotient[2]); 499 | STORE(stepCounter, 65535 & stepCounter[2]); 500 | STORE(dataField, 65535 & dataField[2]); 501 | STORE(instField, 65535 & instField[2]); 502 | STORE(andLED, 1); 503 | STORE(tadLED, 1); 504 | STORE(iszLED, 1); 505 | STORE(dcaLED, 1); 506 | STORE(jmsLED, 1); 507 | STORE(jmpLED, 1); 508 | STORE(iotLED, 1); 509 | STORE(oprLED, 1); 510 | STORE(pauseLED, 1); 511 | STORE(linkLED, 1); 512 | STORE(deferLED, 1); 513 | STORE(wordCountLED, 1); 514 | STORE(currentAddressLED, 1); 515 | STORE(breakLED, 1); 516 | STORE(ionLED, 1); 517 | STORE(fetchLED, 1); 518 | break; 519 | case 6: // 110 = Binary Clock 520 | currentTime = time(NULL); 521 | localTime = localtime(¤tTime); 522 | hour = localTime->tm_hour; 523 | min = localTime->tm_min; 524 | sec = localTime->tm_sec; 525 | 526 | STORE(programCounter, hour); 527 | STORE(memoryAddress, min); 528 | STORE(memoryBuffer, sec); 529 | STORE(accumulator, (localTime->tm_mon + 1)); 530 | STORE(multiplierQuotient,localTime->tm_mday); 531 | STORE(stepCounter, 0); 532 | STORE(dataField, 0); 533 | STORE(instField, 0); 534 | //STORE(linkLED, rand_flag(100,20)); 535 | // Reset the Link light (bug fixed in v2.01 by David C. Eilering) 536 | STORE(linkLED, 0); 537 | STORE(deferLED, 0); 538 | STORE(wordCountLED, 0); 539 | STORE(currentAddressLED, 0); 540 | STORE(breakLED, 0); 541 | STORE(ionLED, 1); 542 | STORE(fetchLED, 1); 543 | // Randomly blink first column of operation LEDs 544 | STORE(andLED, rand_flag(100,50)); 545 | STORE(tadLED, rand_flag(100,5)); 546 | STORE(iszLED, rand_flag(100,10)); 547 | STORE(dcaLED, rand_flag(100,10)); 548 | STORE(jmsLED, rand_flag(100,10)); 549 | STORE(jmpLED, rand_flag(100,30)); 550 | STORE(iotLED, rand_flag(100,20)); 551 | STORE(oprLED, rand_flag(100,20)); 552 | // Override Sleep Time to 0.5 second 553 | sleepTime = 500000; 554 | break; 555 | case 5: // 101 = Fewer Random LEDs 556 | STORE(programCounter, rand() & programCounter[2]); 557 | STORE(memoryAddress, rand() & memoryAddress[2]); 558 | STORE(memoryBuffer, rand() & memoryBuffer[2]); 559 | STORE(accumulator, 0); 560 | STORE(multiplierQuotient,0); 561 | STORE(stepCounter, 0); 562 | STORE(dataField, 0); 563 | STORE(instField, 0); 564 | //STORE(linkLED, rand_flag(100,20)); 565 | // Reset the Link light (bug fixed in v2.01 by David C. Eilering) 566 | STORE(linkLED, 0); 567 | STORE(deferLED, 0); 568 | STORE(wordCountLED, 0); 569 | STORE(currentAddressLED, 0); 570 | STORE(breakLED, 0); 571 | STORE(ionLED, 1); 572 | STORE(fetchLED, 1); 573 | // Randomly blink first column of operation LEDs 574 | STORE(andLED, rand_flag(100,50)); 575 | STORE(tadLED, rand_flag(100,5)); 576 | STORE(iszLED, rand_flag(100,10)); 577 | STORE(dcaLED, rand_flag(100,10)); 578 | STORE(jmsLED, rand_flag(100,10)); 579 | STORE(jmpLED, rand_flag(100,30)); 580 | STORE(iotLED, rand_flag(100,20)); 581 | STORE(oprLED, rand_flag(100,20)); 582 | break; 583 | case 1: // 001 = Snake 584 | switch(y) 585 | { 586 | case 1: 587 | STORE(programCounter, x & programCounter[2]); 588 | STORE(memoryAddress, 0); 589 | STORE(memoryBuffer, 0); 590 | STORE(accumulator, 0); 591 | STORE(multiplierQuotient,0); 592 | break; 593 | case 2: 594 | STORE(programCounter, 0); 595 | STORE(memoryAddress, x & memoryAddress[2]); 596 | STORE(memoryBuffer, 0); 597 | STORE(accumulator, 0); 598 | STORE(multiplierQuotient,0); 599 | break; 600 | case 3: 601 | STORE(programCounter, 0); 602 | STORE(memoryAddress, 0); 603 | STORE(memoryBuffer, x & memoryBuffer[2]); 604 | STORE(accumulator, 0); 605 | STORE(multiplierQuotient,0); 606 | break; 607 | case 4: 608 | STORE(programCounter, 0); 609 | STORE(memoryAddress, 0); 610 | STORE(memoryBuffer, 0); 611 | STORE(accumulator, x & accumulator[2]); 612 | STORE(multiplierQuotient,0); 613 | break; 614 | case 5: 615 | STORE(programCounter, 0); 616 | STORE(memoryAddress, 0); 617 | STORE(memoryBuffer, 0); 618 | STORE(accumulator, 0); 619 | STORE(multiplierQuotient, x & multiplierQuotient[2]); 620 | break; 621 | default: 622 | y = 1; 623 | } 624 | if(shift_dir == 1 && x < 14336) 625 | { 626 | x = x << 1; 627 | if(x < 7) 628 | x += 1; 629 | } 630 | else if(shift_dir == 0 && x > 1) 631 | { 632 | x = x >> 1; 633 | } 634 | else 635 | { 636 | shift_dir = !shift_dir; 637 | y++; 638 | } 639 | 640 | 641 | STORE(stepCounter, 0); 642 | STORE(dataField, 0); 643 | STORE(instField, 0); 644 | STORE(linkLED, 0); 645 | STORE(deferLED, 0); 646 | STORE(wordCountLED, 0); 647 | STORE(currentAddressLED, 0); 648 | STORE(breakLED, 0); 649 | STORE(ionLED, 1); 650 | STORE(fetchLED, 1); 651 | // Randomly blink first column of operation LEDs 652 | STORE(andLED, rand_flag(100,50)); 653 | STORE(tadLED, rand_flag(100,10)); 654 | STORE(iszLED, rand_flag(100,20)); 655 | STORE(dcaLED, rand_flag(100,20)); 656 | STORE(jmsLED, rand_flag(100,20)); 657 | STORE(jmpLED, rand_flag(100,60)); 658 | STORE(iotLED, rand_flag(100,40)); 659 | STORE(oprLED, rand_flag(100,40)); 660 | 661 | // Don't include random delay in snake mode (added v2.10 by David C. Eilering) 662 | sleepTime = delayAmount; 663 | break; 664 | 665 | // break; 666 | 667 | case 2: //010 pong / bouncing ball (by Norman Davie) 668 | { 669 | static long xDirection = 1; 670 | static long yDirection = 1; 671 | static long ball = 1; 672 | static long yBall = 1; 673 | 674 | ClearAllLEDs(); 675 | 676 | // switch directions if we're too far right 677 | if ((ball >> 1) < 1) 678 | { 679 | xDirection = 1; 680 | } 681 | 682 | // switch directions if we're too far left 683 | if ((ball << 1) > (unsigned long) memoryBuffer[2]) 684 | { 685 | xDirection = 0; 686 | } 687 | 688 | if (xDirection) 689 | { 690 | ball = ball << 1; 691 | } 692 | 693 | if (xDirection) 694 | ball = ball << 1; 695 | else 696 | ball = ball >> 1; 697 | 698 | yBall = yBall + yDirection; 699 | switch(yBall) 700 | { 701 | case 0: // too far up 702 | yDirection = 1; 703 | yBall = 1; 704 | break; 705 | case 6: // too far down 706 | yDirection = -1; 707 | yBall = 5; 708 | } 709 | 710 | // store the value in the appropriate row 711 | switch(yBall) 712 | { 713 | case 1: 714 | STORE(multiplierQuotient, ball); 715 | break; 716 | case 2: 717 | STORE(accumulator, ball); 718 | break; 719 | case 3: 720 | STORE(memoryBuffer, ball); 721 | break; 722 | case 4: 723 | STORE(memoryAddress, ball); 724 | break; 725 | case 5: 726 | STORE(programCounter, ball); 727 | break; 728 | default: 729 | break; 730 | } 731 | // sleepTime = 50 * 1000; 732 | // Allow the switches to control the ball speed (added v2.10 by David C. Eilering) 733 | sleepTime = delayAmount; 734 | 735 | } 736 | break; 737 | 738 | case 4: // text scroller (by David C. Eilering) 739 | STORE(stepCounter, 0); 740 | STORE(dataField, 0); 741 | STORE(instField, 0); 742 | STORE(linkLED, 0); 743 | 744 | if (msgPos == 0 && charPos == 0) { 745 | loadMsg(msg); 746 | msgLen = strlen(msg); 747 | } 748 | 749 | // invalid character - skip it 750 | if (msg[msgPos] < 32 || 126 < msg[msgPos]) { 751 | msgPos++; 752 | msgPos = msgPos % msgLen; 753 | break; 754 | } 755 | 756 | if (letterGap < 0) { 757 | letterGap = 1; 758 | } 759 | 760 | // get letter 761 | charNum = (strchr(chars, msg[msgPos]) - chars); 762 | 763 | if (charPos == 0) { 764 | currChar = letters[charNum]; 765 | charWidth = currChar & 0x07; 766 | currChar = currChar >> 3; 767 | // currChar = currChar >> (charPos * 5 + 3); 768 | } 769 | else { 770 | currChar = currChar >> 5; 771 | } 772 | 773 | if (currChar & 1) 774 | bank1++; 775 | 776 | if (currChar & 2) 777 | bank2++; 778 | 779 | if (currChar & 4) 780 | bank3++; 781 | 782 | if (currChar & 8) 783 | bank4++; 784 | 785 | if (currChar & 16) 786 | bank5++; 787 | 788 | charPos++; 789 | 790 | if (charPos >= (charWidth + letterGap)) { 791 | charPos = 0; 792 | msgPos++; 793 | msgPos = msgPos % msgLen; 794 | } 795 | 796 | // display the banks 797 | STORE(programCounter, bank1 & programCounter[2]); 798 | STORE(memoryAddress, bank2 & memoryAddress[2]); 799 | STORE(memoryBuffer, bank3 & memoryBuffer[2]); 800 | STORE(accumulator, bank4 & accumulator[2]); 801 | STORE(multiplierQuotient,bank5 & multiplierQuotient[2]); 802 | 803 | // shift the banks 804 | bank1 = (bank1 << 1) & bankMask; 805 | bank2 = (bank2 << 1) & bankMask; 806 | bank3 = (bank3 << 1) & bankMask; 807 | bank4 = (bank4 << 1) & bankMask; 808 | bank5 = (bank5 << 1) & bankMask; 809 | 810 | sleepTime = delayAmount / 2; // half the delay for text scroll 811 | 812 | break; 813 | 814 | default: 815 | STORE(programCounter, rand() & programCounter[2]); 816 | STORE(memoryAddress, rand() & memoryAddress[2]); 817 | STORE(memoryBuffer, rand() & memoryBuffer[2]); 818 | STORE(accumulator, rand() & accumulator[2]); 819 | STORE(multiplierQuotient,rand() & multiplierQuotient[2]); 820 | STORE(stepCounter, rand() & stepCounter[2]); 821 | STORE(dataField, rand() & dataField[2]); 822 | STORE(instField, rand() & instField[2]); 823 | STORE(linkLED, rand_flag(100,20)); 824 | STORE(deferLED, 0); 825 | STORE(wordCountLED, 0); 826 | STORE(currentAddressLED, 0); 827 | STORE(breakLED, 0); 828 | STORE(ionLED, 1); 829 | STORE(fetchLED, 1); 830 | // Randomly blink first column of operation LEDs 831 | STORE(andLED, rand_flag(100,50)); 832 | STORE(tadLED, rand_flag(100,10)); 833 | STORE(iszLED, rand_flag(100,20)); 834 | STORE(dcaLED, rand_flag(100,20)); 835 | STORE(jmsLED, rand_flag(100,20)); 836 | STORE(jmpLED, rand_flag(100,60)); 837 | STORE(iotLED, rand_flag(100,40)); 838 | STORE(oprLED, rand_flag(100,40)); 839 | break; 840 | } 841 | } 842 | else 843 | { 844 | sleepTime = 250 * 1000; 845 | } 846 | 847 | // Subtract the delay added below 848 | if(sleepTime > opled_delay) 849 | sleepTime = sleepTime - opled_delay; 850 | else 851 | sleepTime = 0; 852 | 853 | // Output Console when register switches change 854 | if(swRegValue != GETSWITCHES(swregister)) 855 | { 856 | swRegValue = GETSWITCHES(swregister); 857 | printf("Register Switch: Value=%lu delay=%lu varietyMult=%lu \n", swRegValue, delayAmount, varietyMult); 858 | 859 | } 860 | 861 | // Output Console when register switches change 862 | if(swStepValue != GETSWITCHES(step)) 863 | { 864 | swStepValue = GETSWITCHES(step); 865 | printf("Step Switch: Value=%lu Mode=%i IF Value=%i\n", swStepValue, deeperThoughtMode, swIfValue); 866 | 867 | } 868 | 869 | // Random Delay 870 | usleep(sleepTime); 871 | 872 | // if the stop switch is held for > 3 seconds, then clean up nicely 873 | if (GETSWITCH(stop)) 874 | { 875 | stopPressedTime = (unsigned long)(stopPressedTime + ((sleepTime + opled_delay) / 1000.0f)); 876 | if(stopPressedTime > 3000) 877 | { 878 | //if(swIfValue==0) 879 | if(GETSWITCH(singStep) && GETSWITCH(singInst)) 880 | { 881 | system("shutdown --poweroff now"); 882 | } 883 | else 884 | { 885 | terminate = 1; 886 | } 887 | } 888 | } 889 | else 890 | { 891 | stopPressedTime = 0; 892 | } 893 | 894 | // if the start switch is held for > 3 seconds, and both Sing switchs are down, reboot system 895 | if (GETSWITCH(start)) 896 | { 897 | startPressedTime = (unsigned long)(startPressedTime + ((sleepTime + opled_delay) / 1000.0f)); 898 | if(startPressedTime > 3000) 899 | { 900 | //if(swIfValue==0) 901 | if(GETSWITCH(singStep) && GETSWITCH(singInst)) 902 | { 903 | system("reboot"); 904 | } 905 | } 906 | } 907 | else 908 | { 909 | startPressedTime = 0; 910 | } 911 | 912 | // if one of the single step switches is selected, then "pause" and don't change the LED display 913 | // otherwise "run" 914 | dontChangeLEDs = GETSWITCH(singStep) || GETSWITCH(singInst); 915 | STORE(pauseLED, dontChangeLEDs); 916 | STORE(runLED, ! dontChangeLEDs); 917 | 918 | // Turn operation LEDs off for 10ms to create a fast blink 919 | STORE(executeLED, 0); 920 | STORE(andLED, 0); 921 | STORE(tadLED, 0); 922 | STORE(iszLED, 0); 923 | STORE(dcaLED, 0); 924 | STORE(jmsLED, 0); 925 | STORE(jmpLED, 0); 926 | STORE(iotLED, 0); 927 | STORE(oprLED, 0); 928 | usleep(opled_delay); 929 | } 930 | 931 | 932 | if( pthread_join(thread1, NULL) ) 933 | printf( "\r\nError joining multiplex thread\r\n" ); 934 | 935 | return 0; 936 | } 937 | --------------------------------------------------------------------------------