***************************************************************************
*Fuzzy Inference Engine For 68k Family Processors
*Run And Tested on hc332 But May Be used on any 68k family part. Uses no
*Special Instructions (I Have My eye on the tbls Instruction for a 332
*Specific Version.
*This Version USes a 68hc11 Style data base with the directives changed to
*Match 68k assemblers. It pretty much
*follows the flow of the hc11 version, and I have even Used the same labels
*where possible. Some optimizations may be possible on this code, and I will
*look into that shortly
*8/17/92
*Harry Powell
*****************************************************************************

code	     equ       0
data	     equ       1	  ;For Section Directives
*
*These 2 Variables Defined For Target Application
csect	     equ       $40000	  ;Beginning Of Code Section
Ram_Beg     equ    $50000	  ;Beginnig Of Ram Free Area

*****************************************************************************
*Knowledge Base Goes Here

*	Generated by KBG.EXE V2.20

*Knowledge Base Ends Here
*****************************************************************************
*Start Of Engine

	    section data
	    ORG     $0000      ;Mpu332 Ram

*Fuzzy Ram Stuff Is defined As Offsets
CURRENT_INS ds.w    NUMINP	;Storage for 8-bit inputs
FUZ_INS     ds.w    8*NUMINP	;Storage for fuzzy inputs (RIGHT NOW MAX=8)
FUZ_OUTS    ds.w    8*NUMOUT	;Storage for fuzzy outputs (RIGHT NOW MAX=4)
COG_OUTS    ds.w    NUMOUT	;Defuzzified outputs


	    section    code	  ;For Now On MPU332 Board
	    even
fuzzify     equ       *
	    movem.l    d0-d7/a0-a3,-(sp)
	    move.l     #Ram_Beg,a0	     ;a0 is Base Address Pointer
	    lea        FUZ_INS(a0),a3
	    lea        CURRENT_INS(a0),a2
	    move.w     #NUMINP-1,d7  ;Loop Counter Used During Fuzzification
	    lea        INPUT_MFS(pc),a1   ;a1 Points To Input Memberships
nxtin_lp     equ       *	  Get Next Input Value
	    move.w     #7,d6	  ;Loop Thru Counter For 8 Labels (use dbf)
	     move.w    (a2)+,d0

grad_loop    equ       *
*******************************************************************
* GET_GRADE - Routine to project a discrete input value onto	  *
*   the associated input membership function (fuzzification).	  *
*   Enter with Input value in d0.w  and a1 pointing at the    *
*   points and slopes defining the membership function. 	  *
*   Finishes with grade in d1, a1 points at next MF spec (a1+8)      *
*   and d0 is unchanged.					   *
*******************************************************************
*Note Use Of Word Addresses For Offsets of Membership Functions
*  0 -> pt1
*  2 -> Slope 1
*  4 -> pt2
*  6 -> Slope 2
pt2	     equ       4
slope1	     equ       2
pt1	     equ       0
slope2	     equ       6

GET_GRADE    equ       *
	     clr.w     d1
	     move.w    pt2(a1),d2   ;Temp Storage For pt.2
	     cmp.w     d0,d2
	     bhi       not_seg2
	     move.w    slope2(a1),d5   ;Get Slope 2
	     beq       hav_grad   ;Vertical So Membership = 0
	     move.w    d0,d4
	     sub.w     d2,d4	  ;Get Distance Beyond pt2
	     mulu      d4,d5	  ;And Project Membership
	     cmp.w     #$ff,d5
	     ble       no_fix	  ;See If Out Of Membership On High End
	     bra       hav_grad   ;Yes So Grade = 0
no_fix	     equ       *
	     move.w    #$ff,d1	  ;Max Possible Membership Value
	     sub.w     d5,d1	  ;Max- (Slope * pt2)
	     bra       hav_grad
*****************************************************************************
*Here The Point Is In Segment 1 or Maybe Less Than Point 1
not_seg2     equ       *	  ;Input Is In Segment 1
	     move.w    (a1),d5	 ;Get Point 1
	     cmp.w     d0,d5	 ;See If Point 1 Is Higher Than Input
	     bhi       hav_grad  ;Yes, Then Membership Is 0
	     move.w    d0,d3	  ;Working Copy Of Input
	     sub.w     d5,d3	  ;d3 gets Distance "into" mfs
	     move.w    2(a1),d4   ;Slope In First Segment
	     beq       vert_slp   ;Vertical Slope
	     mulu      d4,d3	  ;Slope * Distance "Into" Membership
	     cmp.w     #$00ff,d3
	     bhi       vert_slp
	     move.w    d3,d1	  ;Get Result Into Expected Register
	     bra       hav_grad
vert_slp     move.w    #$ff,d1	  ;Either Limit Region OR Vertical Slope
hav_grad     lea       8(a1),a1   ;Next MemberShip Function
	     move.w    d1,(a3)+   ;Store In Fuzz Input For This Member
	     dbf       d6,grad_loop  ;Have we read In 8 members ?
	     dbf       d7,nxtin_lp   ;Have We Read In All Current Inputs ?

***************************************************************************
*All Inputs Are Now Fuzzified, Evaluate Rules Next
***************************************************************************

	     lea       FUZ_OUTS(a0),a1
	     move.w    #NUMOUT,d0
	     asl.w     #3,d0	    ;Quick x8 For 8 Labels Per Output
	     subq.w    #1,d0	  ;Off 1 For dbf
clr_outs     clr.w     (a1)+
	     dbf       d0,clr_outs   ;All Outs Start At 0
	     lea       FUZ_OUTS(a0),a3
	     lea       FUZ_INS(a0),a2
	     lea       RULE_START(pc),a1  ;Start Of First Rule
RULE_TOP     move.w    #$ff,d0	  ;d0 will wind Up with MIN of "IF" Part
IF_LOOP      clr.w     d1	  ;So LAter Shift won't mess up
	     move.b    (a1)+,d1    ;Rules are still expressed as bytes
	     bmi       THEN_LOOP  ;If Bit 7 is 1 then it's a "THEN" Part
	     asl.w     #1,d1	  ;x2 for Word Addressing Of Inputs
	     cmp.w     (a2,d1.w),d0
	     bls       IF_LOOP	  ;If Value In d0 is lower then don't replace
	     move.w    (a2,d1.w),d0  ;ELse Replace with lower Value
	     bne       IF_LOOP	  ;If Not zero the check for more "IF" Parts
*Zero Fuzzy Value Means Rule Is Not True, So Skip To "THEN" Part
FIND_THEN    tst.b     (a1)+
	     bpl       FIND_THEN  ;Keep Looping Until "THEN" Is Hit
FIND_IF      move.b    (a1),d1
	     bpl       RULE_TOP   ;Next "IF" Part
	     lea       1(a1),a1   ;Jump To Next Rule
	     cmp.b     #$ff,d1
	     bne       FIND_IF
	     bra       DEFUZ	  ;If $ff Is Hit Then End Of RUles, Go Defuz

*d0.w has fuzzy value for this Output
THEN_LOOP    and.w     #$7f,d1
	     asl.w     #1,d1	  ;Offset For Word Addressing
	     cmp.w     (a3,d1.w),d0
	     blt       NOT_HIER   ;Fuzzy Value In Output IS Already Higher
	     move.w    d0,(a3,d1.w)
NOT_HIER     tst.b     (a1)
	     bpl       RULE_TOP   ;Another "IF" Part
CHK_END      clr.w     d1
	     move.b    (a1)+,d1
	     cmp.w     #$ff,d1	  ;See If End Of All Rules
	     bne       THEN_LOOP
DEFUZ	     lea       SGLTN_POS(pc),a1  ;First Output Singleton Position
	     lea       FUZ_OUTS(a0),a2
	     lea       COG_OUTS(a0),a3
	     moveq     #NUMOUT-1,d6  ;Count Thru Outputs (use dbf Instr.)
COG_LOOP     clr.l     d0
	     clr.l     d1	  ;Sum Of Products
	     clr.l     d2	  ;Is Sum Of Fuzzy Outputs
	     moveq     #7,d7	  ;8 (-1) Loops Per Output
SUM_LOOP     move.w    (a2)+,d3    ;Get A Fuzzy Output
	     add.w     d3,d2	  ;Add Up Sum Of Fuzzy Outputs
	     move.w    (a1)+,d4   ;Get Output Singleton
	     mulu      d4,d3	  ;Times Fuzzy Output
	     add.l     d3,d1	  ;Add Up Sum Of Products
	     dbf       d7,SUM_LOOP ;8 Hits Thru Loop
	     tst.w     d2	  ;Check For 0 Divide
	     bne       sl1
	     clr.w     d1
	     bra       sl2
sl1	     divu      d2,d1	  ;SOP/SOF A LOT Neater Than hc11 !
sl2	     move.w    d1,(a3)+   ;SAve In COG Output
	     dbf       d6,COG_LOOP ;Do Another Output
*********************************************************************
*All Fuzzy Processing Done Here
*********************************************************************
	     movem.l   (sp)+,d0-d7/a0-a3  ;Give Back Registers
here	     bra       here	   ; Hang here
