    .title Mattel Football Proto

;www.seanriddle.com/footballproto.html
;from patent wrapper for US4162792
;prototype Mattel Football game using 6502
;RAM at 0000 (at least 64 bytes)
;ROM at 0080-00ff, 0200-059F 0600-???? and 0C00-E2B (probably 1K at 0200, 0600 and 0C00)
;reset code at 0200, IRQ at 0227
;also needs RAM at 0100 for stack
;two 6530 RRIOTs at 1000 and 1700
;seven 7-segment LEDs ## ### ##
;27 LEDs for players (9x3) (possibly nine 7-segment LEDs, using only horizontal segments A G and D)
;probably a 7442 to select digit/player column 0-8

;my hardware has two 6532 RIOTs, one 2732 EPROM and a GAL for address decoding
;see footballproto.pld for GAL programming
;128 bytes RAM at 0000, 128 bytes RAM at 0100-017f (mirrored to 0180-01ff)
;4K ROM from 0000-0FFF (accessed at 0080-00ff, 0200-09FF and 0c00-0fff)

;hand-written on printout:
;Cross-assembled on Digital Equip. Corp. PDP-10
;To be run on MOS Technology 6502
;George J. Klose {listed as one of the inventors in the patent}
;1/11/77

;assembly was created 03-SEP-76 at CalTech
;originally two separate code files plus missing data

;code issues
;lots of undefined symbols in patent listing
;missing initializers, tables
;names were converted from >6 chars to 6 chars, some missed
;some typos
;some code seems incorrect (look for === in comments)
;partial conversion from MM:SS time display to TT.T 
;pages out of order
;no schematics or part list

;some vestiges of the driving game remain: Y is horizontal because the display was rotated from vertical,
;there's an unused variable named "ogear", and player LEDs are accessed with "carseg"

;differences from Mattel game:
;no Kick button
;no difficulty switch
;beeps when first down achieved
;starts on 40 yard line instead of 20
;no change in possession at half
;no game over after 4th quarter

;version 1.0 11/19/2016 SKR
;assembled with as6500 v511 http://shop-pdp.net/ashtml/asxxxx.htm
;as6500 -l -o -s footballproto.asm
;aslink -s -m -u -b zprom=0x0080 -b lowrom=0x0200 -b midrom=0x0600 -b highrom=0x0c00 -b vectors=0x0ffa footballproto.rel
;srec_cat footballproto.s19 -o footballproto.bin -binary

;my notes are in {brackets}
    
;;;page 1
;
; variables
;
    who=2
    looker=3
    oldsw=4
    temp=5
    trialx=6
    trialy=7
    manx=8                             ; {8 bytes - up to 8 men - value = row 1 to 3 for top to bottom}
    many=0x10                          ; {8 bytes - up to 8 men - value = column 0 to 8 for left to right}
    bar=0x18
    odist=0x1a
;   ogear=0x1b                         ; {for driving game - not used for football}
    mcycle=0x1c
    whostp=0x1d                        ; {was wstep}
    tkler=0x1e
    state=0x1f
    defh=0x20
    defl=0x21
    blinky=0x22
    note=0x23
    rate=0x24
    tempoh=0x25
    tempol=0x26
    down=0x27
    togo=0x28
    los=0x29
    poss=0x2a
    sleft=0x2b
    sright=0x2c
    jump1=0x2d                         ; {was jumper - next byte needs to be initialized with address high byte of table, dntab, scrtab (4)}
    bptime=0x2f
;;;page 2
    nposs=0x30
    timel=0x31
    timeh=0x32
    timeyl=0x33
    timeyh=0x34
    buzzy=0x35
    bztime=0x36
    losfix=0x37
    button=0x38
    whom=0x39

    shifty=0x3f                        ; {not defined}

    timedp=0x50                        ; {added - display DP in time remaining}

    rand=0x5e                          ; {written in}
    addend=0x5f                        ; {written in}

                                       ; {RIOT1}
    swipia=0x1700                      ; {Up/Down/Adv/Score/Downs/x/x/spkr}
    manpia=0x1702                      ; {vertical field position 1, 2, 4}
    
                                       ; {RIOT0}
    digpia=0x1000                      ; {horizontal field position 0-8 to 7442}
    segpia=0x1002                      ; {A/B/C/D/E/F/G/DP}
    tmrreg=0x101e                      ; {RIOT0 timer, divide by 64, IRQ}
    

; {ROM @ $0080}
.area    zprom  (REL,CON)
; {table of values and addresses to set up PIAs}
; {RIOT0 A=digpia=uuuuOOOO, B=segpia=OOOOOOOO}
; {RIOT1 A=swipia=IIIIIuuO, B=manpia=uuuuuOOO} {0=Input, 1=Output u=Unused, set to Output}
iotab:
    .db 7
    .dw swipia+1                       ; {RIOT1 DDRA:buttons and speaker}
    
    .db 0xff
    .dw manpia+1                       ; {RIOT1 DDRB: field LED row 1=top, 2=middle, 4=bottom}
    
    .db 0xff
    .dw digpia+1                       ; {RIOT0 DDRA: file LED column 0=left, 8=right; also digits 12-345-78 for my display}
    
    .db 0xff
    .dw segpia+1                       ; {RIOT0 DDRB: segments A/B/C/D/E/F/G/DP}
    
    .db 0                              ; {RIOT1 disable A7 edge detect}
    .dw swipia+4
    
    .db 0                              ; {RIOT0 disable A7 edge detect}
    .dw digpia+4

    .db 8                              ; {approx 2 KHz : 6530/6532 timer 1MHz / 64 / 8 = 1953Hz}
    .dw tmrreg    
iotabn:

; {ROM @ $0200}
.area    lowrom  (REL,CON)
;
; main
; here to cold start the program
;
main:   sei                            ; protect ourselves
        
        ldx    #0xff                   ; {added; stack was not initialized}
        txs                            
                
        jsr    setio                   ; set up PIA, vectors, etc
        jsr    setvar                  ; set up impure data base
        cli
        jmp .                          ; this is the entire background program
;
;
; init hardware
; this routine uses a table of addresses and data
; to all of the mixed up memory references
; required to init a PIA
;;;;;;;
; of course it would be possible to replace this
; with a lot of LDA#...STA... code
; {this code assumes iotab in ZP}
setio:  ldx    #<iotab                 ; table of data,addrl,addrh,data,addrl...
setiol: lda    0,x
        inx                            ; x now points to addr for this data
        sta    [0,x]                   ; indexed, indirect
        inx
        inx    
        cpx    #<iotabn    
        bne    setiol
        rts
;
;
; initialize variable
; this uses a table containing the initial values
; of all the variables (i.e. vartab, which is in higher memory)
;;;page 3
; to set the values of the page zero stuff at the
; start of each game    
setvar: ldx    #nvars
setvl:  dex
        lda    vartab,x
        sta    0,x
        cpx    #0
        bne    setvl
        rts
;
;
; interrupt service
; the rest of the program runs in the foreground
; IRQ is connected to the timer in the 6530 {6532}
; clock interrupts occur at 2KHz
; (NMI is not used by the program)
clock:
; we start by saving the registers
        pha
        txa
        pha
        tya
        pha
; now to retrieve the old flags and check for BRK bit
; they are buried somewhere in the stack                
        tsx
        inx                            ; one for y
        inx                            ; one for x
        inx                            ; one for a
        inx                            ; and one for Chuck Peddle {designer of 6502} {gets the status byte position}
        lda    0x100,x                 ; stack starts at 100
        and    #0x10                   ; BRK bit {typo in code:#10 instead of #$10}
        beq    .+5                     ; {was bne, but B=0 means IRQ ===}
        jmp    crash                   ; program error!!!!!!
;
        lda    #8
        sta    tmrreg                  ; approx 2 KHz {was timer} {6530/6532 timer 1MHz / 64 / 8 = 1953Hz} {also enables interrupts}
;
; now we have taken care of all the overhead
; let's go do some useful work
;
        cld                            ; decimal mode stinks
        jsr    serve
;
; put everything back as it was
;
;;;page 4
        pla
        tay
        pla
        tax
        pla
        rti                            ; {code had rts ===}
;
;
; here if a break was executed
; make a noise
;
crash:  sei                            ; pioff just in case
crashl: jsr    audio
        jsr    wait
        jmp    crashl
;
;
; here on each clock tick after saving regs
; 
; the prog is divided into 5 or 6 major states
; 0: run in progress
; 1: not used
; 2: wait at L.O.S. for first step
; 3: show downs
; 4: show score
; 5: runner tackled (blink)
;
; this routine is just five way indexed jump
; depending on the variable 'state'
;
serve:  lda    state
        bmi    .                       ; negative=out of range
        cmp    #5+1                    ; last state + 1
        bpl    .                       ; too big
                                       ; multiply by three
        clc
        asl    a                       ; mult by two
        clc
        adc    state
; add in LSB of table address
; at this point AC contains state*3
        clc
        adc    #<table                 ; {was statetab}
        sta    jump1
        jmp    [jump1]
;
;
; state 0: run in progress
;;;page 5
;
state0: jsr    shomen
        jsr    stepqb
        jsr    defend
        jsr    beeper
        jsr    buzzer
        jsr    timer
        rts
;
;,.
;
; state 5: qb tackled (blink)
;
state5: jsr    shomen
        jsr    blink
        jsr    ss
        rts
;
;;;
;
; state 3: show downs
;
state3: jsr    ss
        jsr    showdn
        rts
;
;*#
;
;state 4: show scores
;
state4: jsr    ss
        jsr    shoscr
        rts
;
;
; state 2: L*O*S*
;
state2:
; detect first action
; set state to zero as soon as player pushes a switch
        jsr    shomen                  ; {added - otherwise display is blank}
        lda    swipia                  ; {was switch}
        eor    #0xff
        tax                            ; {added - save buttons for Score/Down check}
        and    #0xe0                   ; {Up/Down/Advance}
        beq    notmov                  ; {added - not pressed}
        lda    #0
        beq    chgst                   ; {added - branch always - skip new code}
notmov:                                ; {added}
        txa                            ; {added - check for Score or Downs pressed}
        and    #0x10                   ; {added - Score pressed?}
        beq    notsc                   ; {added - no}
        lda    #4                      ; {added - yes, set state 4}
        bne    chgst                   ; {added - branch always}
notsc:                                 ; {added}
        txa                            ; {added}
        and    #0x08                   ; {added - Downs pressed?}
        beq    noswi                   ; {added - no}
        lda    #3                      ; {added - yes, set state 3}
chgst:
        sta    state
; since we don't know what switch were pushed when
;  the last play stopped, trick the debouncer
;;;page 6
; into thinking none were
        lda    #0xff
        sta    oldsw
noswi:        
; if the game clock has expired, this is
; the time to restart it
        lda    timeh
        bmi    s2s                     ; negative means expired
        rts
;
s2s:    lda    itimeh
        sta    timeh
        lda    itimel
        sta    timel
        rts
;
; call here once a tick to multiplex the
; men on the display
;
; >>> note: this routine is highly non-reentrant
; it uses the counter 'whom' to indicate
; which man gets shown during this tick
;
shomen: lda    whom                    ; negative values used to intensify
        bpl    notbrt                  ; {added}
        ldx    #0                      ; the QB who is man #0
        beq    shomn2                  ; {added}
notbrt: tax                            ; {added}
shomn2:                                ; {added}
                                       ; now we have chosen who to show
        jsr    show1                   ; set up the LEDs    
                                       ; now update counter for next time
        dec    whom
        lda    whom
        cmp    #0xf0                   ; this number sets qb intensity
                                       ; the more negative, the brighter
        bne    shms                    ; {shms not in source, so guessed at location below}
        lda    #0x0a                   ; 7 plus three for clock
        sta    whom
shms:                                  ; {is this the correct place?}
        rts
;
;
; state shifters
;
; these routines look at the mode switch
; and alter the state variable accordingly
;
; they respect the mcyclee flag
;
ss:     dec    shifty
;;;page 7
        beq    .+3
        rts
        lda    ishfty
        sta    shifty
;
        jsr    gtmode                  ; (1234)
        cmp    #3
        bpl    .+5
        jmp    req2                    ; so he wants mode 2!
;
        sta    state
        lda    #20
        sta    button
        lda    mcycle
        bne    .+3
        rts
        lda    #0
        sta    mcycle
        jsr    setmen
        rts
;
; here to read and decode the mode bits
; this routine returns a number (1234)
; representing the mode the guy wants
; {downs=3, score=4, movement=2}
;
gtmode: lda    swipia
        eor    #0xff
        lsr
        lsr
        lsr
        clc
        adc    #0x01
        and    #0x03
        clc
        adc    #0x01
        rts
;
;
; set men to their lineup position
;
setmen: ldx    #0x10                   ; {16 bytes, so both manx and many}
setl:   dex
        lda    imanx,x
        sta    manx,x
        cpx    #0
;;;page 8
        bne    setl
;
        lda    nposs
        sta    poss
        rts
; here when no mode switches pushed
; i.e. he wants mode 2
;
; we won't let him have mode 2 until
; the hold timer expires
;
req2:   lda    button
        bne    .+3
        rts
        dec    button
        beq    .+3
        rts
        lda    #2
        sta    state
        rts
;
;
; here to set LEDs to show one man
; call with whom index in X
;
show1:
; **kludge**
; the following code checks to see if X indicates
; that we should not display a man
; if so, display a clock digit instead
        cpx    #8
        bcc    sh1s                    ; {was blt}
        txa
        sec
        sbc    #6                      ; man #8 goes to clock 2
        sta    who
        jsr    shoscr
sh1s:   jsr    farout
        lda    poss                    ; {was possess}
        bne    strate                  ; {was bnz}
                                       ; here if the field is not reflected
        lda    #8
        sec
        sbc    many,x
        bpl    sh1x                    ; always branch!
;
;;;page 9
strate: lda    many,x
sh1x:   sta    digpia
        lda    manx,x
        bpl    sh1s3
        lda    #0
sh1s3:  tax
        lda    carseg,x                ; {carseg=[0,1,2,4]}
        sta    manpia
        rts
;
;
; here to blank the whole display
; in such a way that no 'ghosts' are left
;
farout: lda    #0
        sta    segpia                  ; {was segport}
        sta    manpia                  ; {was manport}
        lda    #0xf
        sta    digpia                  ; {was digport}
        rts
;
;
; here to keep the game clock up to date
;
timer:
; first, we count interrupts
; so that we tick at the proper rate
        inc    timeyl
        beq    .+3
        rts
        inc    timeyh
        beq    .+3
        rts
        lda    itimyh
        sta    timeyh
; here at half second ticks
; check if the timer expired last time
; if so, cause a long buzz sound
        lda    timel
        ora    timeh                   ; if both zero, then expired
;;;page 10
        beq    buzz
; now check if it has been expired for a long time
; if so, do not keep counting
; let it stop at zero!!!
        lda    timeh
        bpl    .+3
        rts                            ; here if sign bit was set
                                       ; here if we are going to decrement the timer
        lda    #5                      ; cause a ticking sound
        sta    bztime
        lda    timel
        clc
        sed
        adc    #0x99                   ; decrement decimal {was #99}
        sta    timel
        cld
        cmp    #0x99                   ; necessary {was #0}
        bne    quit                    ; {was bpl}
; here if the seconds part underflowed
; set it to 59 and 'borrow' out of minutes
; {orig game is not MM:SS; there are 150 ticks, shown as 15.0}
                
;       lda    #0x59                   ; {not needed}
;       sta    timel                   ; {not needed}
        lda    timeh
        sed
        clc
        adc    #0x99
        sta    timeh
;
quit:   cld
        rts
; here when we first notice it has gone to zero
; make a noise and stop the clock by turning on
; the sign bit
buzz:   lda    #0xff
        sta    bztime
        lda    #0x80    
        sta    timeh                   ; stop timer at zero
        rts
;
;
; audio routines 
;**
;first, the low frequency buzz
;
;;;page 11
buzzer: dec    buzzy
        beq    .+3                     ; {was bne ===}
        rts
        lda    ibuzzy
        sta    buzzy
;
        lda    bztime
        bne    .+3
        rts
;
        jsr    audio
        dec    bztime
        rts
;
;
; high frequency beep
;
beeper: lda    bptime
        bne    .+3
        rts
        jsr    audio
        dec    bptime
        rts
;
;
; general purpose routine to output half a cycle
; to the speaker
;
audio:  lda    swipia
        eor    #0x01
        sta    swipia
        rts
;
;
; calliope
;
; high class routine to play music
;
; songs are stored in RAM
; one note per byte
; 02 would be a high note, 40 a low note
; the song is terminated by a zero byte
; call with index to first byte of song in AC
; (index = address - 0600)
;
; note that this routine has to turn off the
; interrupt system (then restores it)
; it would be wise to call farout before 
;;;page 12
; playing a song of any length
; but that is the caller's responsibility
;
; calliope has a fast tempo (used for whistles)
; calliope2 has a slower tempo (used for charge)
cliope:
        ldx    #0xfe                   ; fast rate
        bne    clipes
cliop2:
        ldx    #0xe0                   ; slower {was f7}
clipes: stx    rate
        stx    tempoh                  ; {added so first note is correct ===}
;
        php                            ; save interrupt mask
        sei                            ; we need the whole CPU ourselves
        tax
        jsr    pipeld
        plp                            ; restore interrupt mask
        rts
;
;
; pipe***the guts of calliope    
;
; the entry point is at pipeload
; do not jsr playit!!!!
;
; this routine is organized as two independent counters
; the first one counts how long between
; switching the audio
; the other counts how long we hold the note
;
; naturally, the frequency counter underflows many times per note
; so we have to restore it and count again
; until the tempo counter expires
; then we increment x and use the next byte of the song
; to determine the frequency
;
playit: lda    note
        bmi    nope                    ;rest a note
        dec    note
        bne    nope
; here when the note overflowed
; reset counter and goose the speaker
pipeld:
        lda    song,x
        bne    .+3                     ; {was bmi - typo? ===}
        rts
        sta    note
        jsr    audio
;;;page 13
; here if we don't want to output anything this time through
; count the tempo
nope:   inc    tempol
        bne    playit
        inc    tempoh
        bne    playit
; reset temp counter and go to next note
        lda    rate
        sta    tempoh
        inx                            ;go to next note of song
        jmp    pipeld
;
;
; this routine marks the QB and tackler
; so that they will not be displayed
;
; it sets the sign bit of the manx
;
blink:  inc    blinky
        beq    .+3
        rts
        lda    iblnky
        sta    blinky
;
        ldx    tkler
        lda    manx
        bmi    blinkq
; here to turn off the QB and turn on the tackler
        ora    #0x80
        sta    manx
        lda    manx,x
        and    #0x7f
        sta    manx,x
        rts
; here to do the reverse
blinkq: and    #0x7f
        sta    manx
        lda    manx,x
        ora    #0x80
        sta    manx,x
        rts
;
;
; show downs
;
; this is gigantic signpost branch
; depending on the variable 'who'
;
showdn: jsr    showkl                  ; calculate who*3
        clc
        adc    #<dntab                 ; lsb
;;;page 14
        sta    jump1                   ; {was jumper}
        jmp    [jump1]                 ; {was jumper}
        
; {dntab, scrtab and table all have to be in the same page and 
; jump1+1 needs to be initialized to that page (in this case, page 4)}
; {I modified these tables for the display I used}
;
dntab:                                 ; {was downtab}
        jmp    rts3                    ; {was sd0}
        jmp    sd0                     ; {nothing} {was sd1}
        jmp    sd1                     ; {down} {was rts3}
        jmp    sd3                     ; {field pos}
        jmp    sd4                     ; {field pos}
        jmp    sd5                     ; {field pos}
        jmp    rts3
        jmp    sd7                     ; {yards to go}
        jmp    sd8                     ; {yards to go}
;
;**
;
scrtab:                                ; {was scoretab}
        jmp    rts3                    ; {was ss0}
        jmp    ss0                     ; {home score} {was ss1}
        jmp    ss1                     ; {home score} {was rts3}
        jmp    ss3                     ; {time remaining}
        jmp    ss4                     ; {time remaining}
        jmp    ss5                     ; {time remaining}
        jmp    rts3
        jmp    ss7                     ; {visitor score}
        jmp    ss8                     ; {visitor score}
;
;
;**
;
table:
        jmp    state0
        jmp    .
        jmp    state2
        jmp    state3
        jmp    state4
        jmp    state5
;
; show kludge
; a) updates who
; b) sets digport equal to who {now digpia}
; c) returns 3*who in AC
;;;page 15
; d) clears segments
;
showkl: inc    who
        lda    who
        bmi    krump
        cmp    #0x09
        bmi    shokl2
; here when we have shown everybody once
; start again at 0
krump:  lda    #0
        sta    who
shokl2: ldy    #0
        sty    segpia
        sty    manpia
        sta    digpia
        clc
        asl
        clc
        adc    who
        rts
;
; 
; showdn is a sow
; these are the piglets
;
sd1:
        ldx    down                    ; {added}
        lda    seg7,x                  ; {was segmnt}
        sta    segpia
        rts
; these routines must make special checks
; so they can display the LOS in the traditional
; 0-to-50-to-0 notation of football yardages
;
sd3:    jsr    fixup
        lda    losfix
        inx
        beq    .+5
        jmp    line1                   ; {was line, also used in high ROM}
        jmp    cvt10x
;
sd4:    jsr    fixup
        lda    losfix
        inx
        beq    .+5
;;;page 16
        jmp    cvt10x
        jmp    cvt1
;
sd5:    jsr    fixup
        lda    losfix
        inx
        beq    .+5
        jmp    cvt1
        jmp    line1                   ; {was line}
;
; 
; here to set flags for 0-50-0
;
; there are four cases:
;  1) -->, LOS > 50 (47')
;  2) -->, LOS < 50 ('47)
;  3) <--, LOS > 50 ('47)
;  4) -->, LOS < 50 (47')
;
; this sets losfix to be the yardage
; in the other notation and returns with x set to ff
; in cases 2 and 3 so you can do an inx and branch
; to decide which half of the field you are on
fixup:  lda    los
        ldx    #0
        cmp    #0x50
        bmi    nofix
        lda    #0
        sed
        sec
        sbc    los
        cld
        sta    losfix
        lda    poss
        bne    .+4
        ldx    #0xff
        rts
;
nofix:  sta    losfix
        lda    poss
        beq    .+4
        ldx    #0xff
        rts
;
; 
; these two routines must check for the
; special case where LOS<togo
; if so, pretend togo replaced by LOS
;
; we have to make some weird decisions
; because Chuck {Peddle} was too lazy to put in
;;;page 17
; the full complement of branches
;
sd7:    lda    los
        cmp    togo
        bcc    sd7x
        lda    togo
sd7x:   jmp    cvt10x
;
sd8:    lda    los
        cmp    togo
        bcc    sd8x
        lda    togo
sd8x:   jmp    cvt1
;
line1:  lda #2                         ; {was line - 2=segment G}
        sta    segpia
        rts
;
;
; here to convert the higher halfbyte of AC
; to seven-segment code and store it in  segpia
;
cvt10x: lsr
        lsr
        lsr
        lsr
        jmp    cvt1
;
; here for low order halfbyte
;
cvt1:   and #0xf
        tax
        lda    seg7,x
        ora timedp                     ; {added to display DP for time}
        sta segpia
        lda #0                         ; {added}
        sta timedp                     ; {added}
        rts
;
; same as cvt10x but suppresses leading zeroes
;
cvt10b: lsr
        lsr
        lsr
;;;page 18
        lsr
        beq    storit
        tax
        lda    seg7,x
storit: sta    segpia
        rts
;
;
; show scores and clock
;
shoscr:
        jsr    showkl
        clc
        adc    #<scrtab
        sta    jump1
        jmp    [jump1]
;
;
ss0:    lda    sleft
        jmp    cvt10b
;
ss1:    lda    sleft
        jmp    cvt1
;
ss3:    lda    timeh                   ; {was timel}
;       jmp    cvt10x                  ; {I commented this out}
        jmp    cvt1                    ; {how was this reached originally?}
;
ss4:
        lda    #1
        sta    timedp
        lda    timel                   ; {Mattel game has decimal point here}
        jmp    cvt10x
;
ss5:    lda    timel
        jmp    cvt1
;
ss7:    lda    sright
        jmp    cvt10b
;
ss8:    lda    sright
        jmp    cvt1
;
;
;**
;

    

; {function stubs and empty data tables}

; {todo: figure out what sd0 should do, see if wait needs to do anything}
rts3:
sd0:                                   ; {likely just an RTS}
        rts

wait:                                  ; {only used in case of crash, so likely not important - kill a few hundred cycles}
        ldx    #0
waitl:
        dex
        bne    waitl
        rts
    
nmi:
        rti

; {ROM @ $600-$9FF}
.area  midrom  (REL,CON)
; {song data missing, so captured sound output from Mattel Football}
; {02 would be a high note, 40 a low note}
song:

charge:                                ; {charge must come first because bne used on #tweet1 and #tweet2}
;{160 cycles of  708 Hz}
;{192 cycles of  976 Hz}
;{192 cycles of 1152 Hz}
;{256 cycles of 1400 Hz}
;{192 cycles of 1152 Hz}
;{256 cycles of 1400 Hz}
        .db    31,21,17,14,17,14,0

tweet2:
;{48 cycles of 2088 Hz}
;{48 cycles of 2088 Hz}
;{48 cycles of 2485 Hz}
;{48 cycles of 2485 Hz}
;{64 cycles of 3066 Hz}
;{48 cycles of 2485 Hz}
;{64 cycles of 3066 Hz}
;{48 cycles of 2485 Hz}
;{64 cycles of 3066 Hz}
;{48 cycles of 2485 Hz}
;{64 cycles of 3066 Hz}
;{48 cycles of 2485 Hz}
;{64 cycles of 3066 Hz}
;{48 cycles of 2485 Hz}
;{64 cycles of 3066 Hz}
;{48 cycles of 2485 Hz}
;{64 cycles of 3066 Hz}
;{48 cycles of 2485 Hz}
;{64 cycles of 3066 Hz}
;{48 cycles of 2485 Hz}
        .db    4,4,3,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3

tweet1:
;{48 cycles of 2088 Hz}
;{48 cycles of 2088 Hz}
;{48 cycles of 2485 Hz}
;{48 cycles of 2485 Hz}
;{64 cycles of 3066 Hz}
;{48 cycles of 2485 Hz}
;{64 cycles of 3066 Hz}
;{48 cycles of 2485 Hz}
;{64 cycles of 3066 Hz}
;{48 cycles of 2485 Hz}
;{64 cycles of 3066 Hz}
;{48 cycles of 2485 Hz}
;{64 cycles of 3066 Hz}
;{48 cycles of 2485 Hz}
;{64 cycles of 3066 Hz}
;{48 cycles of 2485 Hz}
;{64 cycles of 3066 Hz}
;{48 cycles of 2485 Hz}
;{64 cycles of 3066 Hz}
;{48 cycles of 2485 Hz}
        .db    4,4,3,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,0
        
; {carseg contains the data to output to the playfield LEDs for the players}
; {todo: fill in carseg}
carseg:
        .db    0
        .db    1
        .db    2
        .db    4
        .db    0
        .db    0
        .db    0
        .db    0    
        
; {seg7 contains the data to output to the score 7-segment LEDs for each digit to display}        
seg7:                                  ; A/B/C/D/E/F/G/DP
        .db    0xfc                    ; 0
        .db    0x60                    ; 1
        .db    0xda                    ; 2
        .db    0xf2                    ; 3
        .db    0x66                    ; 4
        .db    0xb6                    ; 5
        .db    0x3e                    ; 6
        .db    0xe0                    ; 7
        .db    0xfe                    ; 8
        .db    0xe6                    ; 9
        .db    0xee                    ; A
        .db    0x3e                    ; b
        .db    0x9c                    ; C
        .db    0x7a                    ; d
        .db    0x9e                    ; E
        .db    0x8e                    ; F

; {todo: fill in vartab with initial values of variables}
; {table of values to initialize the variables - not defined}
; {some variables are reloaded in the code, hence the specific labels)
; {WAG indicates wild-ass guess}
vartab:
        .db    0
        .db    0
        .db    0                       ;02 who
ilkr:   .db    3                       ;03 looker - WAG
        .db    0                       ;04 oldsw
        .db    0                       ;05 temp
        .db    0                       ;06 trialx
        .db    0                       ;07 trialy
imanx:  .db    2                       ;08    manx
        .db    1
        .db    2
        .db    3
        .db    2
        .db    2
        .db    0
        .db    0
        .db    8                       ;10 many
        .db    5
        .db    5
        .db    5
        .db    3
        .db    0
        .db    0
        .db    0
        .db    0                       ;18 bar
        .db    0xd                     ;19 high byte of address of incded
        .db    0                       ;1A odist
        .db    0
        .db    0                       ;1C mcycle
        .db    0                       ;1D whostp
        .db    0                       ;1E tkler
        .db    2                       ;1F state
idefh:  .db    0xfa                    ;20 defh - WAG
        .db    0                       ;21 defl
iblnky: .db    0x80                    ;22 blinky - WAG
        .db    0                       ;23 note
        .db    0                       ;24 rate
        .db    0xfe                    ;25 tempoh - should be one of the "rate" values from cliope
        .db    0                       ;26 tempol
        .db    1                       ;27 down
        .db    0x10                    ;28 togo
        .db    0x60                    ;29 los
        .db    0                       ;2A poss
        .db    0                       ;2B sleft
        .db    0                       ;2C sright
        .db    0                       ;2D jump1
        .db    4                       ;2E    high byte of address of table, dntab, scrtab
        .db    0                       ;2F bptime
        .db    0                       ;30 nposs
itimel: .db    0x50                    ;31 timel
itimeh: .db    1                       ;32 timeh
        .db    0                       ;33 timeyl
itimyh: .db    0xfa                    ;34 timeyh - adjust for 1/2 second ticks
ibuzzy: .db    0x40                    ;35 buzzy - WAG
        .db    0                       ;36 bztime
        .db    0                       ;37 losfix
        .db    0                       ;38 button
        .db    0x0a                    ;39 whom - shomen re-inits whom to 0x0a
        .db    0
        .db    0
        .db    0
        .db    0
ishfty: .db    3                       ;3f shifty - WAG
        .db    0
        .db    0
        .db    0
        .db    0
        .db    0
        .db    0
        .db    0
        .db    0
        .db    0
        .db    0
        .db    0
        .db    0
        .db    0
        .db    0
        .db    0
        .db    0
        .db    0
        .db    0
        .db    0
        .db    0
        .db    0
        .db    0
        .db    0
        .db    0
        .db    0
        .db    0
        .db    0
        .db    0
        .db    0
        .db    0
        .db    0                       ;5e rand
        .db    0                       ;5f addend

        nvars = 0x60


; {ROM @ $C00-$FFF}
.area  highrom  (REL,CON)
;
; now for the fun part
; this routine looks at the switches, debounces them
; and decides how to move the QB
;
; it checks for hitting a defender
;   running off the end
;   reaching the end zone
;   trying to run off the sides
;

stepqb:
;first, the rate-limiting and debouncing
        dec    looker
        beq    .+3
        rts
        lda    ilkr                    ; {I guessed 3}
        sta    looker
;
; here to look for an edge
; the interesting bits are $E0
; positive edge means that the bit was
; one last time and zero this time
;
        lda    swipia
        tax
        eor    #0xff
        and    oldsw
        and    #0xe0
        stx    oldsw
;
;
; at this point, AC contains 1's for every new bit
;>>>Note: this means that if the player
; managed to hit switches simultaneously, all but one
;;;page 3b
; would be 'lost', because this routine grabs all bits
; but only one will get processed.
;
;
; here with a bit in the AC
; indicating which direction to go
;
doplay:
        pha
        ldx    #0                      ; we want to move man #0
        jsr    try
;
        pla                            ; {added}
        asl
        bcc    notup
; here if he wants to move 'up'
        dec    trialx
        jmp    fin
;
notup:  asl
        bcc    notdn
; here to move down
        inc    trialx
        jmp    fin
;
notdn:  asl
        bcc    rts1
        jsr    adv
        jmp    fin
;
;
; common code for all QB motions
;
fin:    jsr    nforce                  ; check for off sides
        jsr    hitdef                  ; check for collisions
        bcs    tkl
; here if motion is illegal
; move QB to his new place
;
;>>>>>this ldx not in manuscript!!???
        ldx    #0
        jsr    untry
rts1:
        rts
;
; here when there is a tackle due to motion of QB
; (as opposed to motion of tackler!)
tkl:    txa                            ; whodunnit?
        jsr    tackle
        rts
;
;;;page 4b
;
; here to advance QB one step
; (a subroutine of stepqb)
;
adv:    dec    trialy
        bpl    advs
        jsr    offend                  ; wrap around to beginning
;
advs:   jsr    hitdef                  ; if someone's in your way
        bcc    yards
        rts                            ; you cannot make yards!!
;
yards:  lda    togo
        beq    line2                   ; {was line, already used in low ROM}
        clc
        sed                            ; {subtract 1 in decimal mode}
        adc    #0x99                   ; {was #99}
        cld
        sta    togo
        cmp    #0                      ; necessary!!!!
;>>>>decimal mode add does not set Z flag correctly
        bne    line2                   ; {was line}
        jsr    frstdn
;
line2:  lda los                        ; {was line}
        clc
        sed
        adc    #0x99                   ; {was #99}
        cld    
        sta    los
        cmp    #0
        bne    .+5
        jsr    td
        rts
;
; here when QB gets tackled
; AC contains who did it
;
tackle: sta    tkler                   ; {was from tackler}
        jsr    farout
; check to see if he went ten yards or more
; if so, give him a first&ten
;
        lda    togo
        beq    frst10
; no first ---- let's see which song to play
; one tweet if down 1, 2, 3
; two tweets if 4th down, loss of possession
        inc    down                    ; he got tackled, new down #
;;;page 5b
        lda    down
        cmp    #5
        beq    loss
;
        lda    #<tweet1
        bne    coda                    ; always {was bnz}
loss:   jsr    stloss                  ; change possession
        lda    #<tweet2
        bne    coda                    ;{branch always}
;
frst10: jsr    setdn
        lda    #<tweet1
;
coda:
; here with song # in AC
        jsr    cliope
        lda    #5
        sta    state
        lda    #0xff
        sta    mcycle
        rts
;
;
; here to credit him with a first and ten
;
setdn:  lda    #0x10
        sta    togo
        lda    #1
        sta    down
        rts
;
; here when he loses possession
;
stloss: lda    poss
        eor    #0xff
        sta    nposs
        lda    #0
        sec
        sed
        sbc    los
        cld
        sta    los
        jsr    setdn                   ; other guy gets first & ten
        rts
;
;
;;;page 6b
; here when QB crosses tenth yard
; reqard him with a beep
;
frstdn: lda    #0xff
        sta    bptime                  ; {was from beeptime}
        rts
;
; here when he makes a touchdown
;
td:
        lda    #0xff
        sta    tkler                   ; no tackler, no blink
;
        lda    #5                      ; 'hold' mode
        sta    state
    
;
; the condition we impose for resuming play
; is that the player look at his score or downs
; the mcyclee flag keeps us from going to state 2 until
; he does
        lda    #0xff
        sta    mcycle                  ; {was mustcycl}
;
        jsr    farout
        lda    #<charge
        jsr    cliop2
; now give his opponent a turn
        lda    poss
        eor    #0xff
        sta    nposs
; don't forget to give him his points
        eor    #0xff
        and    #1
        tax
; at this point, x=0 for left, x=1 for right
        lda    sleft,x
        clc
        sed
        adc    #7
        cld
        sta    sleft,x
; the other guy takes over on the 40
; i.e. 60 yards to go
        lda    #0x60
;;;page 7b
        sta    los
        jsr    setdn
        rts
;
;
; simple routine to reset QB to back of field
;
offend: lda    #8
        sta    trialy
        rts
;
; here to check if a man tried to go off the sides
; works for QB and others
;
nforce: lda    trialx
        bne    enfs                    ; {was bnz}
        lda    #1
        sta    trialx
;
enfs:   cmp    #4
        bmi    enftop
        lda    #3
        sta    trialx
;
enftop: lda    trialy
        bpl    enfbot
        lda    #0
        sta    trialy
enfbot: cmp    #9
        bmi    enfend
        lda    #8
        sta    trialy
enfend: rts
;
;
; defense motion
;
defend:
        inc    defl
        beq    .+3
        rts
        inc    defh
        beq    .+3
        rts
;
        jsr    random
        sta    defl                    ; partly random rate
        lda    idefh
;;;page 8b
        sta    defh
        jsr    stepx
        rts
;
;
; choose a random defender
;
stepx:
getx:   jsr    random
        and    #7
        beq    getx                    ; player >0 is defender
; here with candidate in AC
; check how many players are actually on the field
        sta    whostp
        tax
        lda    manx,x
        beq    getx                    ; non-existent man {was getsome}    
; here with real man in whostp
; and in x
        jsr    try
        jsr    stphim
; here to see if it was a legal step
; first, check for tackle
        lda    trialx
        cmp    manx
        bne    team
        lda    trialy
        cmp    many
        bne    team
        lda    whostp
        jsr    tackle
        rts
;
team:   jsr    hitdef                  ; did he hit a teammate?
        bcs    rts2                    ; yes, oh, well; nobody moves this time
    
        ldx    whostp                  ; no, good, put him in a new place
        jsr    untry
rts2:   rts
;
;
; here with some defender named in whostep
; this routine calls trial step until it
; finds a step that puts defender closer to the QB
stphim:
        jsr    gmunu                   ; the metric
;;;page 9b
        sta    odist
stepl:  ldx    whostp
        jsr    try
        jsr    trystp
        
        jsr    nforce                  ; {moved here to fix code below}
        
        jsr    gmunu
        cmp    odist
        bpl    stepl
        rts
;
;
; here to step trialx/y in a random direction
; no guarantee that it is toward QB

;
trystp: jsr    random
        asl
        asl
        and    #0x0c                   ; {rand # is 0, 4, 8 or C}
        clc
        adc    #<incdec
        sta    bar
        
;       jsr    bar                     ; {todo: how was this supposed to work? no indirect jsr ===}
;       jsr    nforce                  ; {moved out of this subroutine to fix}
        
        jmp    [bar]                   ; {my fix}
        
;       rts                            ; {no longer used}
;
;foo:   jmp    [bar]                   ; {never used}
;
incdec:
        inc    trialx                  ; {0}
        rts
        nop
        
        dec    trialx                  ; {4}
        rts
        nop
        
        inc    trialy                  ; {8}
        rts
        nop
        
        dec    trialy                  ; {C}
        rts
;
;
; here to determine if data in trialx/y
; coincides with some defender
;
;;;page 10b
hitdef:
        ldx    #8
hitl:   dex
        bne    check
        clc
        rts
;
check:  lda    manx,x
        cmp    trialx
        bne    hitl
        lda    many,x
        cmp    trialy
        bne    hitl
        sec
        rts
;
;
; these routines copy stuff into trialx/y
; call with man # in X
;
try:    lda    manx,x
        sta    trialx
        lda    many,x
        sta    trialy
        rts
;
untry:  lda    trialx
        sta    manx,x
        lda    trialy
        sta    many,x
        rts
;
;
; the metric
; computes the distance between trial and QB
;
gmunu:
        lda    trialx
        sec
        sbc    manx
        jsr    abs
        sta    temp
        lda    trialy
        sec
        sbc    many
        jsr    abs
        clc
        adc    temp
        rts
;
; absolute value
;
abs:    cmp    #0
        bpl    absend
        eor    #0xff
        clc
        adc    #1
absend: rts
;
;
; random number generator
; r = r * 5 + a
; a = a + 1
; return(r)
;
random: lda    rand
        rol
        rol
        rol
        adc    rand                    ; {actually *9, not *5}
        adc    addend
        sta    rand
        inc    addend
        rts
;
;
; end of the motion package
;

                
; {ROM @ $FFA - decoded at $FFFA}    
.area  VECTORS (REL,CON)
        .globl nmi_addr                ; fffa
        .globl reset                   ; fffc
        .globl irq_addr                ; fffe
        
nmi_addr:
        .dw    nmi
reset:
        .dw    main
irq_addr:
        .dw    clock


