;***** Final Project: BlakJak **********
;Create a simple blackjack game for 8535 board.
;
;Keyboard uses D,LCD uses C

.include     "c:\users\bnj\8535def.inc"
.include     "c:\users\bnj\addldef.inc"                    ;this file is attached at the bottom of this page
.device     AT90S8535

.def     score  =r0                                                ;player $ left
.def     savSREG  =r1                                         ;save the status register
.def     key  =r2                                                  ;holds raw button press value
.def     comp  =r3                                               ;for binary to ascii conversion
.def     RNG  =r4                                               ;RNG register
.def     finalP  =r24                                             ;final point value (w/ aces) of player
.def     acenumP  =r10                                       ;number of aces of player
.def     acevalue =r11                                         ;point value of aces (selected between aceA and aceB)
.def     acenumD  =r12                                       ;number of aces of dealer
.def     finalD  =r26                                            ;final point value (w/ aces) of dealer
.def     cardval  =r14                                          ;value of currently selected card
.def     temp  =r16                                              ;temporary register
.def     state  =r17                                              ;state register
.def     aceA  =r18                                             ;acevalue A
.def     butnum  =r19                                          ;final press value
.def     count  =r20                                             ;counter for writing unshuffled deck
.def     count2  =r21                                           ;second register for unshuffled deck
.def     temp2  =r22                                           ;second temp reg
.def     aceB  =r23                                             ;acevalue B
.def     totalP  =r9                                             ;current accumulated point value (no aces) of player
.def     totalD  =r13                                           ;current accumulated point value (no aces) of dealer
.def     statusbj =r27                                         ;side0---who1---blackjack2---playerbusted3---dlrbusted4
                                                                        ;---playerwins5---even6----who0: 0 = dealer, 1 = player
.def     dlrfrstc =r28                                          ;dealer's first card
.def     cardsP  =r8                                           ;
.def     cardsD  =r15                                        ;
.def     tempmo  =r29                                       ;

;LCD REGISTERS
.def    wreg    =R25                                        ;temp register for interrupts
.def    timeout =R5                                         ;Timeout value passed to subroutine
.def    lcdstat =R6                                          ;LCD busy/wait status
.def    longtime=R7                                        ;Long timer for powerup

;*************
.dseg

;pre-shuffled deck
deck:            .byte 52                                     ;52 cards
decktemp:    .byte 52                                     ;temporary storage of preshuffled

;Shuffled deck
shuffle:         .byte 52                                     ;52 cards
ashuffle:       .byte 52                                     ;ascii version of shuffled deck

;score
scoremem:   .byte 3                                      ;3 digit score (each point representing $10)

;******************
.cseg

.org $0000
             rjmp         RESET                                ;reset entry vector
             rjmp         EXT_INT0                         ;keybd hit
             rjmp         EXT_INT1                         ;keybd stay
             reti
             reti
             reti
             reti
             reti
             reti
             rjmp         T0INT                                  ;timer 0 ovfl intrpt (LCD)
             reti
             reti
             reti
             reti
             reti
             reti
             reti

;define fixed strings to be tranmitted from flash- zero terminated
keytbl:         .db     0b11101110, 0b11101101, 0b11101011, 0b11100111
                   .db     0b11011110, 0b11011101, 0b11011011, 0b11010111
                   .db     0b10111110, 0b10111101, 0b10111011, 0b10110111
                  .db     0b01111110, 0b01111101, 0b01111011, 0b01110111
 

RESET:     ldi         temp, LOW(RAMEND)      ;init stack pointer
                 out        SPL, temp
                 ldi         temp, HIGH(RAMEND)
                 out        SPH, temp

                 ldi         temp,0xc0
                 out       GIFR, temp
                 ldi         wreg, 0b11000000             ;enable external interrupt 1&0
                 out       GIMSK, wreg                      ; (button detection)

                 ldi         state,shuffling                      ;Start state is shuffling

                 clr         butnum                               ;Default=no button pressed
                 ldi         temp,10                             ;
                 mov      score,temp                         ;player gets $100 to start

                 ldi         Temp, TCK1024               ;scale tim1 by 1024 for 1 sec delay
                 out        TCCR1B, Temp                  ;
                 ldi         temp, TCK1                         ;
                 out       TCCR2, temp                     ;Timer 2 at TCK1 speed

;********LCD STARTUP CODE
                ldi         temp,TSTOP                      ;
                out        TCCR0,temp                     ;Timer 0 off (just in case)
                ldi         temp,0b00000001             ;Enable Timer 0 interrupt
                out        TIMSK,temp

                sei                                                    ;global interrupt enabled

                rcall       lcdinit                                  ;Initialize LCD module
                rcall       lcdclr                                   ;Clear LCD screen
                ldi temp, 0xd4                                   ;print score 0 on line 4
                rcall lcdcmd                                      ;
                ldi temp, 0x24                                  ;Initial score=$100
                rcall lcdput                                       ;
                ldi temp, 0x31                                  ;
                rcall lcdput                                       ;
                ldi temp, 0x30                                  ;
                rcall lcdput                                       ;
                ldi temp, 0x30                                  ;
                rcall lcdput                                       ;

;*****statetable select
states:     cpi         state,shuffling                          ;jump to appropriate state
              breq      _shuffling                                  ;see our state diagram
              cpi         state,dealing                              ;
              breq      _dealingPT                              ;
              cpi         state,hitstay                              ;
              breq      _hitstayPT                                  ;
              cpi         state,hit                                      ;
              breq      _hitPT                                       ;
              cpi         state,stay                                  ;
              breq      _stayPT                                   ;
              cpi         state,winner                              ;
              breq      _winnerPT                                  ;
_error:    rjmp      _error                                       ;No match for state; error
 

;*******************************
;Store the preshuffled deck at location "deck"
_shuffling:  ldi         ZL, LOW(deck)                  ;ptr to RAM
                 ldi         ZH, HIGH(deck)
                 ldi         temp, 1
                 ldi         count, 52
                 ldi         count2, 4

                clr         butnum                               ;Default=no button pressed
                clr         cardsP                               ;set # cards for each side to be 0
                 clr         cardsD                               ;

_pilecards: st          Z, temp
                 adiw     ZL, 1
                 dec       count2
                 breq     _incvalue
                 dec      count
                 brne     _pilecards
                 rjmp     _shuffle

_incvalue:  ldi         count2, 4                             ;need to adjust count every 4 cards
                 inc        temp                                   ;increase card value by 1
                 dec       count
                 brne     _pilecards
                 rjmp     _shuffle

;***jump points**
_dealingPT:
                 rjmp     _dealing                                  ;
_hitstayPT:
                 rjmp     _hitstay                                      ;
_hitPT:      rjmp     _hit                                           ;
_stayPT:   rjmp     _stay                                       ;
_winnerPT:
                rjmp     _winner                                   ;
 

;*******************************
;This routine will shuffle the default deck to location "shuffle"
_shuffle:
             ldi             XL, LOW(shuffle)                ;ptr to RAM (shuffled deck)
             ldi             XH, HIGH(shuffle)
             in             rng, TCNT1L                         ;rng will be 7-bit RNG from timer 1
             ldi             count2, 52                             ;need to go through 52 cards
_takecard:                                                         ;Now get new random number, based on previous value
             mov         temp, rng                                ;use temp and temp2 to do RNG
             andi         temp, 0x01
             mov         temp2, rng
             andi         temp, 0x02
             eor          temp, temp2                             ;XOR these last two bits
             ror           temp                                          ;and place into C
             ror           rng                                          ;place C into RNG with a shift

;The # cards remaining affects what our random # should be
;[will want max(random #) = ((# cards) - 1) ]
             mov         temp, rng                                 ;place random number into temp reg
             cpi           count2, 33                             ;if need number > 32,
             brsh         _6rng                                      ; use 6 bits
             cpi c        ount2, 17                                 ;if need number > 16,
             brsh         _5rng                                      ; use 5 bits
             cpi          count2, 9                                 ;if need number > 8,
             brsh         _4rng                                      ; use 4 bits
             cpi          count2, 5                                 ;if need number > 4,
             brsh         _3rng                                      ; use 3 bits
             cpi          count2, 3                                 ;if need number > 2,
             brsh         _2rng                                      ; use 2 bits
             cpi          count2, 2                                 ;if need number > 1,
             brsh         _1rng                                      ; use 1 bit
             cpi          count2, 1                                 ;if need number = 1,
             breq         _0rng                                      ; use final card

             clr             statusbj                                 ;clear black jack status register

             ldi             temp,0b00000001                 ;
             bst            temp,1                                  ;
             bld           statusbj, 1                             ;who bit =0 (dealer)
             bst           temp,0                                  ;
             bld           statusbj, 0                               ;side bit =1 (down)

             clr         count                                      ;count (aka card #) = 0
             clr         acenumP                                  ;clear ace number count for both
             clr         acenumD                                  ;
             clr         totalP                                      ;clear total point value for both
             clr         totalD                                      ;

             ldi         ZL, low(shuffle)                        ;record the dealer first card
             ldi         ZH, high(shuffle)                         ;
             ld         dlrfrstc, Z                                 ;

             ldi         temp,0b00000001                  ;
             bst          temp,0                                   ;
             bld         statusbj, 0                                  ;side bit =1 (down)

             ldi         state, dealing                         ;ELSE LOAD DEALING STATE
             rjmp      states                                         ;

_6rng:    andi         temp, 0x3f                             ;take low 6 bits from RNG
             cp            temp, count2                         ;if RN too big, take less bits
             brsh         _5rng                                      ;
             rjmp        _movecard                             ;else put appropriate card into place

_5rng:    andi         temp, 0x1f                             ;take low 5 bits from RNG
             cp            temp, count2                         ;if RN too big, take less bits
             brsh         _4rng                                      ;
             rjmp        _movecard                             ;else put appropriate card into place

_4rng:    andi         temp, 0x0f                             ;take low 4 bits from RNG
             cp           temp, count2                         ;if RN too big, take less bits
             brsh         _3rng                                      ;
             rjmp        _movecard                             ;else put appropriate card into place

_3rng:   andi         temp, 0x07                             ;take low 3 bits from RNG
             cp           temp, count2                         ;if RN too big, take less bits
             brsh         _2rng                                      ;
             rjmp        _movecard                             ;else put appropriate card into place

_2rng:    andi         temp, 0x03                             ;take low 2 bits from RNG
             cp            temp, count2                         ;if RN too big, take less bits
             brsh         _1rng                                      ;
             rjmp         _movecard                             ;else put appropriate card into place

_1rng:    andi         temp, 0x01                             ;take low 1 bit from RNG
             rjmp         _movecard                             ;else put appropriate card into place

_0rng:    ldi           temp, 0                                    ;
             rjmp        _movecard                                 ;else put last card into place

;Now that card is chosen for shuffled deck, put it in
_movecard:
             clr         count                                          ;gone through 0 cards
             ldi         ZL, LOW(deck)                         ;ptr to RAM (preshuffled)
             ldi         ZH, HIGH(deck)
             ldi         YL, LOW(decktemp)                ;ptr to RAM (decktemp)
             ldi         YH, HIGH(decktemp)

;This loop is made for each card in preshuffled deck
_nextcard:
             ld          temp2, Z                                     ;get next card value
             cp         count, temp                                 ;have we reached card to remove?
             breq     _removecard                                 ;move card to shuffled deck at this point

             st         Y, temp2                                     ;otherwise place card into decktemp
             adiw     ZL, 1                                          ;choose next card to go into temp deck
             adiw     YL, 1                                          ;choose next temp deck spot

             inc         count                                           ;
             cp         count, count2                               ;reached end of deck?
             brne      _nextcard                                     ;
             dec       count2                                          ;one less card in deck
             rjmp     _takecard                                     ;going on to choose next card

;We have reached the card we wish to use in the shuffled deck
_removecard:
             st X,     temp2                                         ;put card taken from preshuffled into shuffled deck
             adiw     ZL, 1                                          ;choose next card to go into temp deck
             adiw     XL, 1                                          ;move shuffled pointer to next spot

             inc         count                                          ;
             cp         count, count2                              ;reached end of deck?
             brne     _nextcard                                     ;
             dec     count2                                              ;one less card in deck
             rjmp     _takecard                                     ;going on to choose next card

;****************
;Dealing state: give two cards to each player
_dealing:
             cpi       count, 4                                      ;check if this is the 5th card
             breq    _nodealing                                  ;if so, go to next state's selection

             rcall     _deal                                           ;give dealer a card

             sbrs     statusbj,1                                      ;check to see which side to display for
             rjmp    _dealeraddr                                  ;if bit cleared, display for dealer

            ldi        temp,0x7f                                    ;change addressing for player
            add     temp,cardsP                                  ;add # cards played
            rcall    lcdcmd                                         ; (1st line)
            rjmp   _writechar                                      ;now write character

_dealeraddr:
             ldi         temp,0xbf                                ;change addressing for dealer
             add       temp,cardsD                              ;add # cards played
            rcall       lcdcmd                                         ; (2nd line)
             mov      temp, statusbj                              ;
             andi     temp, 0x01                                      ;side bit
             brne     _downcard                                  ;side=1 (down)

_writechar:
             mov     temp, cardval                                  ;
             rcall     _cardconv                                      ;convert into ascii
_w2:     rcall     lcdput                                               ;place cardval onto LCD
             cpi      count, 3                                          ;if count <=3 and count=3 or 1
             breq     _dealingP                                      ;then the current card is dealt
             cpi       count, 1                                          ;to the player
             breq     _dealingP  ;

             cpi       count, 2                                              ;if count =2 then the current card
             breq     _dealingD                                          ;is dealt to the dealer

_moredealing:                                                        ;and it remains in dealing state
             rjmp     states                                               ;

_downcard:        ldi temp, 0xff                                  ;dark block (down card)
             rjmp     _w2                                                   ;

_dealingP:
             ldi          temp,0b00000001                              ;
             bst         temp,0                                               ;
             bld         statusbj, 1                                          ;who bit =1 (player)
             bst         temp,1                                               ;
             bld         statusbj, 0                                          ;side bit =0 (up)
             rjmp      _moredealing                                      ;

_dealingD:
             ldi          temp,0b00000001                              ;
             bst         temp,1                                                   ;
             bld         statusbj, 1                                          ;who bit =0 (dealer)
             bst          temp,1                                               ;
             bld         statusbj, 0                                          ;side bit =0 (up)
             rjmp      _moredealing                                      ;

_nodealing:
             rcall      _blackJ                                                ;
             sbrc     statusBJ, 2                                          ;if blackjack bit is set
             rjmp     _towinner                                          ;then go straight to winner state
             ldi        state, hitstay                                      ;otherwise go to hit/stay state
             rjmp     states                                                   ;
_towinner:
             ldi         state, winner                                      ;
             rjmp     states                                                   ;
 ;check blackjack bit in statusbj register
 ;if set then goto state winner
 ;otherwise goto state hitstay

;****************
_hitstay:

             cpi        finalP,21                                             ;auto end if player has 21
             breq     _stay1                                                  ;

           ldi          temp,0xc0
             out         GIFR, temp

             cpi         butnum, 4                                          ;if hit (button 1)
             breq      _tohit                                                   ;then go to state hit
             cpi         butnum, 8                                          ;if stay (button 2)
             brne      _hitstay                                              ;continue

_stay1:  clr         butnum                                               ;RESET BUTNUM AFTER KEYPRESS

             ldi         temp,0b00000001                              ;otherwise goto state stay
             bst         temp,1                                               ;
             bld         statusbj, 1                                          ;who bit =0 (dealer)
             bst         temp,1                                                   ;
             bld         statusbj, 0                                          ;side bit =0 (up)

             ldi         temp,0xC0                                                ;change addressing for dealer
             rcall       lcdcmd                                                     ; (2nd line)
             mov       temp, dlrfrstc                                              ;get label of dealer's first card
             rcall       _cardconv                                                  ;convert into ascii
             rcall       lcdput                                                       ;place dlrfrstc onto LCD

             ldi         state, stay                                                          ;
             rjmp     states                                                               ;
_tohit:    ldi        temp,30                                                 ;delay for button press
             mov     longtime, temp
             clr         temp
             mov     timeout,temp                                            ;Delay 15 mS
puwait3:
            rcall        delay
            ldi           temp,1
            sub         longtime, temp
            brne        puwait3

             clr         butnum                                                   ;RESET BUTNUM AFTER KEYPRESS

             ldi         temp,0b00000001                                  ;otherwise goto state stay
             bst         temp,0                                                   ;
             bld         statusbj, 1                                              ;who bit =1 (player)
             bst          temp,1                                                   ;
             bld         statusbj, 0                                              ;side bit =0 (up)
             ldi         state, hit                                                      ;
             rjmp     states                                                       ;

;*****************
_hit:       rcall      _deal                                                       ;deal player a card

             ldi         temp,0x7f                                                    ;change addressing for player
             add       temp,cardsP                                              ;add # cards played
             rcall       lcdcmd                                                     ; (1st line)
             mov       temp, cardval                                              ;
             rcall       _cardconv                                                  ;convert into ascii
             rcall       lcdput                                                       ;place cardval onto LCD

             rcall      playerfinal                                                      ;

             cpi         finalP, 22                                                      ;
             brsh       _towinner                                                      ;if finalP>21 then to winner state
             ldi          state, hitstay                                                  ;otherwise back to hit/stay state
             rjmp      states                                                               ;

;*****************
_stay:     rcall     dealerfinal                                                          ;
             cpi         finalD, 17                                                      ;
             brsh      _towinner2                                                  ;if finalD >=17 then to state winner
             rcall      _deal                                                           ;otherwise stay in this state
                                                                                             ;and keep dealing cards to dealer

             ldi         temp,0xbf                                                    ;change addressing for dealer
             add       temp,cardsD                                                  ;add # cards played
            rcall        lcdcmd                                                             ; (2nd line)
             mov      temp, cardval                                                      ;
             rcall      _cardconv                                                  ;convert into ascii
             rcall      lcdput                                                           ;place cardval onto LCD
             rjmp     states                                                           ;
_towinner2:
             cpi         finalD, 22                                                      ;
             brlo       _nobustD                                                      ;if finalD <=21 , then no bustD
             ldi         tempmo, 0b00000010                                 ;otherwise
             bst         tempmo, 1                                                  ;
             bld         statusbj,4                                                      ;bustedD bit =1
_nobustD:
             ldi         state, winner                                                  ;
             rjmp      states                                                           ;

;*****************
_winner:
             rcall      playerfinal                                                      ;

            ldi         temp, 0x94                                                          ;print on 3rd line
            rcall       lcdcmd                                                             ;

             sbrc         statusbj,2                                                          ;
             rjmp         _bj                                                               ;if blackjack, then player wins
             sbrc         statusbj,3                                                         ;
             rjmp         _loss                                                               ;if player busted, then player loses
             sbrc         statusbj,4                                                          ;
             rjmp         _win                                                                   ;if dealer busted, then player wins
             mov         temp,finalD                                                          ;
             mov         temp2,finalP                                                      ;
             cp          temp, temp2                                                          ;
             brlo       _win                                                                   ;finalD < finalP, player wins
             breq      _lossoreven                                                          ;if finalD = finalP, player loses or even
             rjmp      _loss                                                                   ;otherwise finalD > finalP, player loses

_bj:       ldi           tempmo, 0b00000010                                         ;
             bst         tempmo, 1                                                             ;
             bld         statusbj, 5                                                             ;player wins bit =1
             inc         score                                                                    ;Give 2x normal win for BJ
             inc         score                                                                    ;
             ldi         temp, 0x42                                                              ;'B'
             rcall         lcdput                                                                   ;
             ldi         temp, 0x4a                                                               ;'J'
             rcall        lcdput                                                                   ;
             rjmp _mopupLCD                                                              ;goto final lcd update
_win:     ldi          tempmo, 0b00000010                                         ;
             bst         tempmo, 1                                                              ;
             bld         statusbj, 5                                                          ;player wins bit =1
             ldi          temp, 0x57                                                          ;'W'
             rcall       lcdput                                                                     ;
             rjmp     _mopupLCD                                                          ;goto final lcd update
_even:   ldi         tempmo, 0b00000010                                                     ;
             bst         tempmo, 1                                                                      ;
             bld         statusbj, 6                                                                   ;even bit =1
             ldi         temp, 0x54                                                                  ;'T'
             rcall      lcdput                &nbs