PIC16F887 control unit


/*
 * step 1: CO MI pulse 
 * step 2: RO II CE pulse
 * step 3: read op-code
 * step 4: based on op-code. 
 * lda: 5: IO MI pulse; 6: RO AI pulse
 * add: 5: IO MI pulse; 6: RO BI pulse 7: ZO AI pulse
 * out: 5: AO OI pulse
 * sta:
 * Created on March 3, 2025, 7:43 PM
 */
// CONFIG1
#pragma config FOSC = INTRC_NOCLKOUT// Oscillator Selection bits (INTOSCIO oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled and can be enabled by SWDTEN bit of the WDTCON register)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = ON       // RE3/MCLR pin function select bit (RE3/MCLR pin function is MCLR)
#pragma config CP = OFF         // Code Protection bit (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Code Protection bit (Data memory code protection is disabled)
#pragma config BOREN = OFF      // Brown Out Reset Selection bits (BOR disabled)
#pragma config IESO = OFF       // Internal External Switchover bit (Internal/External Switchover mode is disabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is disabled)
#pragma config LVP = OFF        // Low Voltage Programming Enable bit (RB3 pin has digital I/O, HV on MCLR must be used for programming)

// CONFIG2
#pragma config BOR4V = BOR21V   // Brown-out Reset Selection bit (Brown-out Reset set to 2.1V)
#pragma config WRT = OFF        // Flash Program Memory Self Write Enable bits (Write protection off)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

#include <xc.h>
#include <pic16f887.h>
#define _XTAL_FREQ 4000000

#define clkin RB0 // external clock
#define RI    RB1  // RAM in, write LOW (default)
#define RO    RB2  //  Ram out, HIGH (def)
#define pulse RB3 // LOW (def)
#define MI    RB4  // MAR, HIGH (def)
#define II    RB5  // HIGH (def)
#define IO    RB6// HIGH
#define AI    RB7 // HIGH

#define in1 RD0 // input
#define in2 RD1               
#define in3 RD2
#define in4 RD3

#define AO RD4 // HIGH
#define ZO RD5 // HIGH
#define SU RD6 // LOW
#define BI RD7 // HIGH

#define OI RC0 // LOW
#define CE RC1  // program counter, LOW
#define CO RC2  // HIGH
#define CI RC3  // jump, HIGH
#define CR RC4 // carry bit LOW

#define res_low  RE0 // reset LOW
#define res_high RE1 // reset HIGH

  
/*  registers needed for external interrupt  
 *  OPTION_REGbits.INTEDG = 1;
    INTCONbits.GIE = 1;
    INTCONbits.PEIE = 1;
    INTCONbits.INTE = 1;
void __interrupt() ISR(void){            
    //RB0 pin for external interrupt 
    //reset the interrupt flag
    if (INTCONbits.INTF == 1) {
        // code here 
        INTCONbits.INTF = 0;
    }
}
*/
    
void main(void) {
    ANSEL = 0x00;
    ANSELH = 0x00;
    TRISB = 0x01; // 0000 0001 all outputs, except PB0 
    PORTB = 0B11110100;
    TRISD = 0x0F; // 0000 1111
    PORTD = 0B10110000;
    TRISC = 0x10 ; // 0001 0000, RC4 input
    PORTC = 0B00001100; 
    TRISE = 0x00; // all outputs
    PORTE = 0B00000010;

    unsigned char opcode = 0;
    unsigned char carry = 0;
    unsigned char next = 0;
    unsigned char step = 1;
    
    // reset
    __delay_ms(100);
    RE0 = 1; 
    RE1 = 0; 
    __delay_ms(200);
    RE0 = 0;
    RE1 = 1;
    

  while(1) {  // endless loop
        
        // first 3 steps is to output the PC, input MAR  (MI CO clk clk CO MI)
        // output RAM, input instruction register, (RO, II clk clk II RO)
        // read op-code 
        
        // control lines based on op-code
     
      if (carry == 1) RC5 = 1; else RC5 = 0;
      if (RB0 == 1) next = 1; else next = 0;
      if (next) {
          next = 0;
          switch (step) {
            case 1:    // fetch step 1 
                  MI = 0;
                  CO = 0;
                  pulse = 1;
                  __delay_ms(20);
                  pulse = 0;
                  MI = 1;
                  CO = 1;
                  __delay_ms(10);
                  step = 2;  // next
                  break;
            case 2:    // fetch step 2
                  RO = 0;
                  II = 0;
                  CE = 1;
                  pulse = 1;
                  __delay_ms(20);
                  pulse = 0;
                  RO = 1;
                  II = 1;
                  CE = 0;
                  opcode = PORTD & 0x0F;
                  __delay_ms(10);
                  step = 3;   // next
                  break;
            case 3: 
                  if (opcode == 0x01) {  //LDA step 1
                      IO = 0;
                      MI = 0;
                      pulse = 1;
                      __delay_ms(20);
                      pulse = 0;
                      IO = 1;
                      MI = 1;
                      __delay_ms(10);
                      step = 4;  // next
                  } else if (opcode == 0x02) {  //ADD step 1
                      IO = 0;
                      MI = 0;
                      pulse = 1;
                      __delay_ms(20);
                      pulse = 0;
                      IO = 1;
                      MI = 1;
                      __delay_ms(10);
                      step = 4;  // next
                  } else if (opcode == 0x03) { // SUB step 1
                      IO = 0;
                      MI = 0;
                      pulse = 1;
                       __delay_ms(20);
                      pulse = 0;
                      IO = 1;
                      MI = 1;
                      __delay_ms(10);
                      step = 4;  // next             
                   } else if (opcode == 0x04) { // STA step 1
                      IO = 0;
                      MI = 0;
                      pulse = 1;
                      __delay_ms(20);
                      pulse = 0;
                      IO = 1;
                      MI = 1;
                      __delay_ms(10);
                      step = 4;  // next
                   } else if (opcode == 0x05) { // LDI
                      IO = 0;
                      AI = 0;
                      pulse = 1;
                      __delay_ms(10);
                      pulse = 0;
                      IO = 1;
                      AI = 1;
                      __delay_ms(10);
                      step = 1;  // start again      
                   } else if (opcode == 0x06) { // JMP
                      IO = 0;
                      CI = 0;
                      pulse = 1;
                      __delay_ms(20);
                      pulse = 0;
                      IO = 1;
                      CI = 1;
                      __delay_ms(10);
                      step = 1;  // start again                           
                   } else if (opcode == 0x07) { // JC    
                      if (carry == 1) {
                          IO = 0;
                          CI = 0;
                          pulse = 1;
                          __delay_ms(20);
                          pulse = 0;
                          IO = 1;
                          CI = 1;
                          __delay_ms(10);  
                      }
                      step = 1;  // start again 
                   } else if (opcode == 0x0E) {  //OUT
                     AO = 0;
                     OI = 1;
                     pulse = 1;
                     __delay_ms(20);
                     pulse = 0;
                     AO = 1;
                     OI = 0;
                     __delay_ms(10);          
                     step = 1;   // start again                                 
                  } else if (opcode == 0x0F) {  // HALT
                     step = 6;   // stop the loop
                  } 
                  break;
            case 4: 
                  if (opcode == 0x01) {  //LDA step 2
                     RO = 0;
                     AI = 0;
                     pulse = 1;
                     __delay_ms(20);
                     pulse = 0;
                     RO = 1;
                     AI = 1;
                     __delay_ms(10);      
                     step = 1;  // start again                           
                  } else if (opcode == 0x02) {  //ADD step 2
                     RO = 0;
                     BI = 0;
                     pulse = 1;
                     __delay_ms(20);
                     pulse = 0;
                     RO = 1;
                     BI = 1;
                     __delay_ms(10);
                     step = 5;  // next          
                   } else if (opcode == 0x03) { // SUB step 2
                     RO = 0;
                     BI = 0;
                     SU = 1;  // keep it high
                     pulse = 1;
                     __delay_ms(20);
                     pulse = 0;
                     RO = 1;
                     BI = 1;
                     __delay_ms(10);
                     step = 5;  // next              
                  } else if (opcode == 0x04) {  //STA step 2
                     AO = 0;
                     RI = 1;
                     pulse = 1;
                     __delay_ms(20);
                     pulse = 0;
                     AO = 1;
                     RI = 0;
                     __delay_ms(10);      
                     step = 1;  // start again                           
                  }
                  break;
            case 5: 
                  if (opcode == 0x02) {  //ADD step 3
                     ZO = 0;
                     AI = 0;
                     if (RC4 == 1) carry = 1; else carry = 0;
                     pulse = 1;
                     __delay_ms(20);
                     pulse = 0;
                     // if (RC4 == 1) carry = 1; else carry = 0;
                     ZO = 1;
                     AI = 1;
                     __delay_ms(10);      
                     step = 1;  // start again                           
                  } else if (opcode == 0x03) {  //SUB step 4
                    ZO = 0;
                    AI = 0;
                    if (RC4 == 1) carry = 1; else carry = 0;
                    pulse = 1;
                    __delay_ms(20);
                    pulse = 0;
                    // if (RC4 == 1) carry = 1; else carry = 0;
                    ZO = 1;
                    AI = 1;
                    SU = 0;
                    __delay_ms(10);      
                    step = 1;  // start again                           
                  }
                  break;
            default:
                  step = 6;
                  break;
      }   // switch
    } // if
    
  }
    return;
}