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;
}