# 2.1 Arithmetic Logic Unit

`module alu ( CLK, CB, WE, B, FI, FO, CI, CO, DC, Z );input CLK;// Clockinput [4:0] CB; // operation codeinput WE; // Write enable for W registerinput [2:0] B; // bit positioninput [7:0] FI; // operandinput CI; // Carry inoutput [7:0] FO; // dest busoutput CO; // Carry outoutput DC; // Half carryoutput Z; // Zeroreg HC; // half carryreg [7:0] W;reg [8:0] tmp;reg [7:0] bit_mask;wire sub;assign sub = ( CB == `ISUB );`
`always @( B )case( B )3'b000: bit_mask = 8'b0000_0001;3'b001: bit_mask = 8'b0000_0010;3'b010: bit_mask = 8'b0000_0100;3'b011: bit_mask = 8'b0000_1000;3'b100: bit_mask = 8'b0001_0000;3'b101: bit_mask = 8'b0010_0000;3'b110: bit_mask = 8'b0100_0000;3'b111: bit_mask = 8'b1000_0000;default: bit_mask = 8'bxxxx_xxxx; endcase`
`always @( CB or FI or W or HC or CI or bit_mask or sub )begin  HC = 1'b0;  casex( CB ) `    IPSW: tmp = { 1'b0, W }; // Pass W register value    `ICLR: tmp = 9'b0_0000_0000; // Clear    `IADD, `ISUB:    begin { HC, tmp[3:0] }= {1'b0,FI[3:0]} + {1'b0, sub? ~W[3:0]:W[3:0]} + sub;                 tmp[8:4] = {1'b0,FI[7:4]} + {1'b0, sub? ~W[7:4]:W[7:4]} + HC; end`
``IDEC1, `IDEC2: tmp = { 1'b0, FI } - 1 ; // Decrement, Decrement and skip if 0`IOR : tmp = { 1'b0, FI } | { 1'b0, W } ; // Logical OR`IAND: tmp = { 1'b0, FI } & { 1'b0, W } ; // Logical AND`IXOR: tmp = { 1'b0, FI } ^ { 1'b0, W } ; // Logical Exclusive OR`IPSF: tmp = { 1'b0, FI } ; // Pass FI`INTF: tmp = { 1'b0, ~FI } ; // Complement FI`IINC1, `IINC2: tmp = { 1'b0, FI } + 1 ; // Increment, Increment and skip if 0`IRRF: tmp = {FI[0], CI, FI[7:1]} ; // Rotate Right through Carry`IRLF: tmp = {FI, CI} ; // Rotate Left through Carry`ISWP: tmp = {1'b0, FI[3:0], FI[7:4]}; // nibble swap`IBCF: tmp = {1'b0, FI} & {1'b0,~bit_mask} ; // bit clear`IBSF: tmp = {1'b0, FI} | {1'b0, bit_mask} ; // bit set`IBTF: tmp = {1'b0, FI} & {1'b0, bit_mask} ; // bit testdefault: tmp = 9'bx_xxxx_xxxx;end caseend`
`// FOassign FO = tmp[7:0] ;// W Registeralways @( posedge CLK )if( WE ) W <= tmp[7:0] ; // Flagassign CO = tmp[8] ; // Carry Borrow flagassign DC = HC ; // Half carry flagassign Z = (tmp[7:0] == 0) ; // Zero flagendmodule`
``define IPSW 5'b00000 // Pass W`define ICLR 5'b00001 // Clear`define ISUB 5'b00010 // Sub`define IDEC1 5'b00011 // Dec`define IOR 5'b00100 // Or`define IAND 5'b00101 // And`define IXOR 5'b00110 // Xor`define IADD 5'b00111 // Add`define IPSF 5'b01000 // Pass F`define INTF 5'b01001 // Not`define IINC1 5'b01010 // Inc`define IDEC2 5'b01011 // Dec`define IRRF 5'b01100 // Rotate Right with carry`define IRLF 5'b01101 // Rotate Left with carry`define ISWP 5'b01110 // Nibble swap`define IINC2 5'b01111 // Inc`define IBCF 5'b100?? // Bit Clear F`define IBSF 5'b101?? // Bit Set F`define IBTF 5'b11??? // Bit Test F`

# 2.2 Core Input, Output, and Register

`// STATUS Register`define STATUS { IRP, RP, nTO, nPD, Z, DC, C }// IR`define IRB IR[ 9:7]`define IRK IR[ 7:0]`define IRF IR[ 6:0]`define IRA IR[10:0]// Memory Address`define A_INDF 7'b000_0000`define A_PCL 7'b000_0010module pic16core ( CLK, RST, RA, RB );input CLK;input RST;inout [7:0] RA;inout [7:0] RB;parameter PROG = "program.mem";// Special Registerreg IRP;reg [1:0] RP;reg nTO, nPD, Z, DC, C; // 03 83 // STATUSreg [7:0] FSR; // 04 84reg [7:0] PORTA, TRISA; // 05 85reg [7:0] PORTB, TRISB; // 06 86reg [4:0] PCLATH; // 0A 8Areg [7:0] RAM[ 12 : 127 ]; // 0C-7F // DATA busreg [7:0] SDATA; // for special registerreg [7:0] RDATA; // for ALU operandwire [7:0] WDATA; // for ALU resultwire [7:0] DDATA; // for Data RAM Read Data// Flag data from ALU to Flag registerwire CO, DCO, ZO; // Control Signalreg NOP_S; // Fetch cancel on CALL, GOTOreg [4:0] ALU_CB; // ALU controlreg W_W; // Write enable for W registerreg C_W, DC_W, Z_W; // Write enable for Flag register (STATUS[2:0])reg F_W; // Write enable for Data memoryreg WDT_C; // WDT clearreg nTO_S, nTO_C; // nTO set and clearreg nPD_S, nPD_C; // nPD set and clearreg SLEEP; // Sleep modereg SLP_S; // Sleep mode set // Registerreg [12:0] PC; // Program Counter { PCH, PCL }reg [13:0] IR; // Instruction Register// Registerreg [12:0] PC; // Program Counter { PCH, PCL }reg [13:0] IR; // Instruction Register`

`// Effective Addresswire [ 8 : 0 ] EA;assign EA = ( `IRF == 0 ) ? { IRP , FSR [7:0] } : { RP , `IRF};`

# 2.4 Program Counter and Return Stack

`// Program Counter & Return Stackreg [ 12:8 ] STK[0:7]; // Return Stack depth 8reg [ 2:0] STKP; // Return stack pointer 4 bitreg STK_PU; // Stack Push enablereg STK_PO; // Stack Pop enablereg PC_W; // Write enable for CALL, GOTO// Program Counteralways @( posedge CLK )if( RST ) PC <= 0; else // RESETif( PC_W ) PC <= {PCLATH[4:3],IR[10:0] }; else // CALL, GOTOif( F_W && EA [6:0] == `A_PCL ) PC <= { PCLATH[4:3], WDATA[7:0] }; else // write PCL register if( STK_PO ) PC <= STK[ STKP-1 ]; else // RETURN, RETLWif( SLEEP || SLP_S ) PC <= PC ; else // SLEEP modePC <= PC + 1;// Return Stackalways @( posedge CLK )beginif( RST ) STKP<= 0 ; else // for Emptyif( STK_PU ) begin STK[ STKP ] <= PC ; STKP<= STKP+1; end else // for CALLif( STK_PO ) STKP<= STKP-1; // for RETxxend`

# 2.5 Instruction Memory and Register

`// Instruction Memory (8k word)reg [ 13 : 0 ] IMEM[ 0 : 8195 ];initialbegin\$readmemh( PROG, IMEM );end// Instruction Registeralways @( posedge CLK )if( NOP_S || PC_W || STK_PO || RST )IR <= 14'b00_0000_0000_0000 ; else // if CALL, RET, cond.SKIPIR <= IMEM[PC] ; // Instruction fetch`

# 2.6 Decode and Control

`// Decode & Controlalways @( IR or ZO )  begin    ALU_CB=IR[ 12 : 8 ];    F_W=0; W_W=0; Z_W=0; DC_W=0; C_W=0; nTO_S=0; nTO_C=0; nPD_S=0; nPD_C=0; STK_PU=0;    STK_PO=0; NOP_S=0; PC_W=0; WDT_C=0; SLP_S=0;    case( IR[ 13 : 12] )      2'b00 :        begin          W_W = ~IR[7] && IR[11:8] != 4'b0000 ;          F_W = IR[7]; //same with W_W = IR[7] && |IR[11:8] meaning bit 8 is 1 and bit 9-12 isn`t 0          case( IR[ 11 : 8 ] )            4'b0000:              case( IR[7] )                1'b0: case( IR[ 6 : 0 ] )                  7'b000_1000 : begin NOP_S=1 ; STK_PO=1 ; end // RETURN               // 7'b000_1001: ; // RETFIE                  7'b110_0011 : begin nTO_S=1; nPD_S=1; WDT_C=1; SLP_S=1 ; NOP_S=1 ; end // SLEEP               // 7'b110_0100: ; // CLRWDT                  default: ; // NOP                  endcase                1'b1: ; // MOVWF f              endcase            4'b0001: begin Z_W=1 ; end // CLRW, CLRF            4'b0010: begin C_W=1 ; DC_W=1 ; Z_W=1 ; end // SUBWF            4'b0011: begin Z_W=1 ; end // DECF            4'b0100: begin Z_W=1 ; end // IORWF            4'b0101: begin Z_W=1 ; end // ANDWF            4'b0110: begin Z_W=1 ; end // XORWF            4'b0111: begin C_W=1 ; DC_W=1 ; Z_W=1 ; end // ADDWF            4'b1000: begin Z_W=1 ; end // MOVF            4'b1001: begin Z_W=1 ; end // COMF            4'b1010: begin Z_W=1 ; end // INCF            4'b1011: begin NOP_S= (ZO==1) ? 1 : 0 ; end // DECFSZ            4'b1100: begin C_W=1 ; end // RRF            4'b1101: begin C_W=1 ; end // RLF            4'b1110: ; // SWPF            4'b1111: begin NOP_S=ZO ; end // INCFSZ          endcase //IR        end        2'b01 :        begin          case( IR[ 11 : 10 ] )            2'b00 : F_W = 1 ; // BCF f, b            2'b01 : F_W = 1 ; // BSF f, b            2'b10 : NOP_S=ZO ; // BTFSC f, b            2'b11 : NOP_S=~ZO ; // BTFSS f, b          endcase        end        2'b10 :            begin              PC_W = 1 ; NOP_S = 1 ;                case( IR[ 11 ] )                  1'b0 : STK_PU = 1 ; // CALL                  1'b1 : ; // GOTO                endcase              end              2'b11 :              begin                W_W= 1 ;                casex( IR[ 11 : 8 ] )                  4'b00xx : begin ALU_CB=`IPSF ; end // MOVLW k //--> pass in ALU to W //                  4'b01xx : begin ALU_CB=`IPSF ; STK_PO = 1 ; NOP_S = 1; end // RETLW k                  4'b1000 : begin ALU_CB=`IOR ; Z_W = 1 ; end // IORLW k                  4'b1001 : begin ALU_CB=`IAND ; Z_W = 1 ; end // ANDLW k                  4'b1010 : begin ALU_CB=`IXOR ; Z_W = 1 ; end // XORLW k                  4'b110x : begin ALU_CB=`ISUB ; C_W=1 ; DC_W=1 ; Z_W = 1 ; end // SUBLW k                  4'b111x : begin ALU_CB=`IADD ; C_W=1 ; DC_W=1 ; Z_W = 1 ; end // ADDLW k                endcase              end            endcase          end // always @ ( IR or ZO )`

# 2.7 Special Register

`// Special Register// Writealways @( posedge CLK or posedge RST )  begin    if( RST )      begin        C = 0 ;        DC = 0 ;        Z = 0 ;        IRP = 0 ;        RP = 2'b00 ;        nTO = 1 ; // nTO=1 on Power-on        nPD = 1 ; // nPD=1 on Power-on        FSR = 0 ; PCLATH = 5'b00000 ;        PORTA = 8'b0000_0000 ;        TRISA = 8'b1111_1111 ; // All ports for input        PORTB = 8'b0000_0000 ;        TRISB = 8'b1111_1111 ; // Table page 18-20      // All ports for input         end       else         begin           // STATUS           if( C_W ) C = CO ;           if( DC_W ) DC = DCO ;           if( Z_W ) Z = ZO ;           if( nPD_S ) nPD = 1'b1;           if( nPD_C ) nPD = 1'b0;           if( nTO_S ) nTO = 1'b1;           if( nTO_C ) nTO = 1'b0;           // Register Write           if( F_W ) //pic16_behaviour page 41             casex( EA ) //effective address           // 9'b?0_000_0001: TMR0 = WDATA; // 01 101 Described TMR0 part //find in address table           // 9'b?1_000_0001:`OPTION = WDATA; // 81 181           // 9'b??_000_0010: PCL = WDATA; // 02 82 102 182 Described PC part              9'b??_000_0011:`STATUS = WDATA; // 03 83 103 183              9'b??_000_0100: FSR = WDATA; // 04 84 104 184              9'b00_000_0101: PORTA = WDATA; // 05              9'b01_000_0101: TRISA = WDATA; // 85              9'b?0_000_0110: PORTB = WDATA; // 06 106              9'b?1_000_0110: TRISB = WDATA; // 86 186              // 9'b??_000_0111: ; // 07              // 9'b??_000_1000: ; // 08 EEDATA not implement              // 9'b??_000_1001: ; // 09 EEADR not implement              9'b??_000_1010: PCLATH = WDATA[4:0]; // 0A 8A 10A 18A              // 9'b??_000_1011:`INTCON = WDATA; // 0B 8B 10B 18B            endcase          end        end`
`// Data RAM (Write)always @( posedge CLK )  begin    if( F_W && ( EA[6:0] >= 7'b001_1000 ) ) RAM[ EA[6:0] ] <= WDATA ; //12-127 PIC16 behaviour p.46 //light behaviour p.41 //Effective Address only 7bit not 9bit start from 12 //store RAM to WDATA  end// Selecter for Special Registeralways @( IR or PC or EA or IRP or RP or nTO or nPD or Z or DC or C // STATUS                  or FSR or RA or TRISA or RB or TRISB or PCLATH )  casex( EA )    // 9'b?0_000_0001: SDATA = TMR0;    // 9'b?1_000_0001: SDATA =`OPTION;    9'b??_000_0010: SDATA = PC[7:0] ; // PCL    9'b??_000_0011: SDATA =`STATUS ; // STATUS    9'b??_000_0100: SDATA = FSR ; // FSR    9'b00_000_0101: SDATA = PORTA ; // RA    9'b01_000_0101: SDATA = TRISA ; // TRISA    9'b?0_000_0110: SDATA = PORTB ; // RB    9'b?1_000_0110: SDATA = TRISB ; // TRISB    9'b??_000_1010: SDATA = {3'b000, PCLATH }; // PCLATH //because SDATA is 9 bit and PCLATH is only 6 bit, we need to add 3 bit before PCLATH // 9'b??_000_1011: SDATA =`INTCON;    default: SDATA = 8'bxxxx_xxxx;  endcase// Data RAM Readassign DDATA = RAM[EA[7:0]] ;`

# 2.8 Data Path

`// Data selector for ALU operandalways @( IR or EA or DDATA or SDATA )  begin RDATA <= 8'bxxxx_xxxx ;  if( &IR[13:12] ) RDATA <= `IRK ; else //    casex( EA )      9'b??_000_0010: RDATA <= SDATA ; // PCL      9'b??_000_0011: RDATA <= SDATA ; // STATUS      9'b??_000_0100: RDATA <= SDATA ; // FSR      9'b0?_000_0101: RDATA <= SDATA ; // PORTA, TRISA      9'b0?_000_0110: RDATA <= SDATA ; // PORTB, TRISB      9'b??_000_1010: RDATA <= SDATA ; // PCLATH      default: RDATA <= RAM[EA[7:0]] ; // Shared memory    endcase  end`

# 2.9 ALU Initiate

`// Execute   alu i_alu ( .CLK(CLK), .CB(ALU_CB), .WE(W_W), .B(`IRB),           .FI(RDATA),           .FO(WDATA),           .CI(C), .CO(CO), .DC(DCO), .Z(ZO) );`

# 2.10 Sleep

`// Sleep modealways @( posedge CLK or posedge RST )begin  if(RST) SLEEP <= 0; else //0 mean run  if(SLP_S) SLEEP <= 1; //1 mean execute the sleep modeend`

# 2.11 Tristate Buffer

`// Tristate buffer for GPIOassign RA[0] = ( TRISA[0] ) ? 1'bZ : PORTA[0];assign RA[1] = ( TRISA[1] ) ? 1'bZ : PORTA[1];assign RA[2] = ( TRISA[2] ) ? 1'bZ : PORTA[2];assign RA[3] = ( TRISA[3] ) ? 1'bZ : PORTA[3];assign RA[4] = ( TRISA[4] ) ? 1'bZ : PORTA[4];assign RA[5] = ( TRISA[5] ) ? 1'bZ : PORTA[5];assign RA[6] = ( TRISA[6] ) ? 1'bZ : PORTA[6];assign RA[7] = ( TRISA[7] ) ? 1'bZ : PORTA[7];assign RB[0] = ( TRISB[0] ) ? 1'bZ : PORTB[0];assign RB[1] = ( TRISB[1] ) ? 1'bZ : PORTB[1];assign RB[2] = ( TRISB[2] ) ? 1'bZ : PORTB[2];assign RB[3] = ( TRISB[3] ) ? 1'bZ : PORTB[3];assign RB[4] = ( TRISB[4] ) ? 1'bZ : PORTB[4];assign RB[5] = ( TRISB[5] ) ? 1'bZ : PORTB[5];assign RB[6] = ( TRISB[6] ) ? 1'bZ : PORTB[6];assign RB[7] = ( TRISB[7] ) ? 1'bZ : PORTB[7];endmodule`

# Mirrors

this blog contains all my articles licensed under creative commons attribution customized sharealike (cc-by-sa) where you can sell but mention the open one here

## More from Fajar Purnama

this blog contains all my articles licensed under creative commons attribution customized sharealike (cc-by-sa) where you can sell but mention the open one here

## Shuffling Up Song Data Management

Get the Medium app