*= $4000;
!to "test.o"
!cpu 6502
; !set simulator = 1
!ifdef simulator {
sensor1 = $c061 ;for
simulation on mac use simulated sw0 input
sensor2 = $c062 ;for simulation
on mac use simulated sw1 inputA
}else{
sensor = $c0c0 ;card
plugged in slot 4
}
keyboard = $c000 ;read from keyboard
frstsensor = $80
secsensor = $40
sensmask = $3f
frstopensecclos = frstsensor OR sensmask
frstclossecopen = secsensor OR sensmask
bothclos = sensmask
bothopen = secsensor OR frstsensor OR sensmask
variables = $fa ; used for onerr pointers by applesoft
variable1 = $eb ;
variable2 = $ce ;
msfrstopen = variables + $0
lsfrstopen = variables + $1
esfrstcls = variables + $2
msfrstcls = variables + $3
lsfrstcls = variables + $4
mssecopen = variable1 + $0
lssecopen = variable1 + $1
esseccls = variable1 + $2
msseccls = variable1 + $3
lsseccls = variable1 + $4
errortn = variable2 + $0 ; error returned
state = variable2 + $1 ; current
state
scratch = $18 ; scratchpad
;
; error codes
;
err_timeout = 1
err_pg1_fail = 2
err_pg2_fail = 3
err_pg3_fail = 4
;
; define commonly used macros
;
;
; increment time (ls byte in x, ms byte in y) - takes 9 cycles
;
!macro inc_time .wrap_exit{
inx
; 2
bne .no_ls_wrap
; 2/3
iny
; 2
bne .no_ms_wrap
; 2/3
jmp .wrap_exit
; 4
.no_ls_wrap
nop
; 2
nop
; 2
.no_ms_wrap
}
;
; save time (ls byte in x, ms byte in y) - takes 10 cycles
;
!macro sv_time_1_opn {
tya
; 2
sta msfrstopen
; 3
txa
; 2
sta lsfrstopen
; 3
}
;
; save time (ls byte in x, ms byte in y) - takes 10 cycles
;
!macro sv_time_1_cls {
tya
; 2
sta msfrstcls
; 3
txa
; 2
sta lsfrstcls
; 3
}
;
; save time (ls byte in x, ms byte in y) - takes 10 cycles
;
!macro sv_time_2_opn {
tya
; 2
sta mssecopen
; 3
txa
; 2
sta lssecopen
; 3
}
;
; save time (ls byte in x, ms byte in y) - takes 10 cycles
;
!macro sv_time_2_cls {
tya
; 2
sta msseccls
; 3
txa
; 2
sta lsseccls
; 3
}
!ifdef simulator {
;
; following code for mac simulator - use mouse buttons
;
;
; read shutter HW and put results into acc
; 18 cycles
;
!macro read_sensor {
lda sensor2
; 4 read sensor2
lsr
; 2 shift right one bit
sta scratch
; 3 save temporary
lda sensor1
; 4 read sensor1
ora #sensmask
; 2 add in unused bits
ora scratch
; 3 merge with other sensor
}
} else {
!macro read_sensor {
lda sensor
; 4 read sensor
}
}
!ifdef simulator {
;
; read shutter HW and wait for change
; 0 cycles setup
; 32 per loop
; -1 final iteration
;
!macro wait_change .current_state, .timeout {
.compare
+inc_time .timeout ;
9 cycles
+read_sensor
; 18
cmp .current_state
; 3 cycles (zero page)
beq .compare
; 2 fall through/3 branch
}
} else {
;
; read shutter HW and wait for change -
; 3 cycles setup (assuming .current_state
is zero page)
; 16 per loop
; -1 final iteration
;
!macro wait_change .current_state, .timeout{
lda .current_state
; 3 cycles (zero page)
.compare
+inc_time .timeout ;
9 cycles
cmp sensor
; 4 cycles
beq .compare
; 2 fall through/3 branch
}
}
.code
;
; initialize variables and clock
;
start
lda #$0
sta msfrstopen ;left
shutter open time
sta lsfrstopen ;
sta esfrstcls ;left
shutter close time
sta msfrstcls ;
sta lsfrstcls ;
sta lssecopen ;right
shutter open time
sta mssecopen ;
sta esseccls ;right
shutter close time
sta lsseccls ;
sta msseccls ;
sta errortn
;initially no error
tax
;initial time is zero
tay
;initial time (most significant) is also zero
.start
lda #bothclos ;initial
state
sta state
;save it
;
; first ensure the shutter is totally closed
;
.wait_till_off
lda keyboard ; has
user typed something?
bpl .wait_off_cont ;
no continue
rts
; yes return to application
.wait_off_cont
+read_sensor ;
cmp state ; are both
sensors off?
bne .wait_till_off ; no, wait
;
; align page 1 to ensure branches don't cross page boundries
;
!align 255,0
;
; OK, we are ready to go, but don't start clock until something happens
;
.wait_4_change
lda keyboard ; has
user typed something?
bpl .wait_change_cont ; no continue
rts
; yes return to application
.wait_change_cont
+read_sensor ;
cmp state ; 3 are
both sensors off?
beq .wait_4_change ; 2/3 yes, wait
;
; Ok, we detected a transition
;
; is is 1st, 2nd or both open?
sta state
; 3 save current state
cmp #bothopen ; 2
check for both open
beq .pg1_both_open ; 2/3 yes,
skip jump
jmp .pg1_chk_1st_open ; 3 branch (this
leads to page 2)
;
; both shutters opened at same time
;
.pg1_both_open
+wait_change state,t12_timeout ; 3(initial)/18(per
loop)/7(exit)
+read_sensor ; 4
sta state ; 3
;
; which shutter closed?
;
cmp #bothclos ; 2
both?
bne .pg1_chk_1st_closed; 2/3 no, try individual
+sv_time_2_cls ;
log times for both channels
+sv_time_1_cls ;
rts
;
; first shutter closed, second still open
;
.pg1_chk_1st_closed
cmp #frstclossecopen ; 2 just first
bne .pg1_chk_2nd_closed; 2/3 no, must
be second
+sv_time_1_cls ;
10
.pg1_1st_cycled
;
; wait for 2nd to close, 1st already cycled
;
+wait_change state,t2_timeout ; 3(initial)/18(per
loop)/7(exit)
+read_sensor ; 4
cmp #bothclos ; 2
sanity check
bne .pg1_fail ; 2/3
branch if error
+sv_time_2_cls ;
10
rts
;
; assume 2nd closed
;
.pg1_chk_2nd_closed
+sv_time_2_cls ;
10
.pg1_2nd_cycled
;
; wait for 1st to close, 2nd already cycled
;
+wait_change state,t1_timeout ; 3(initial)/18(per
loop)/7(exit)
+read_sensor ; 4
cmp #bothclos ; 2
sanity check
bne .pg1_fail ; 2/3
branch if error
+sv_time_1_cls ;
10
rts
.pg1_fail
lda #err_pg1_fail
sta errortn
rts
;
; align page 2 to ensure branches don't cross page boundries
;
!align 255,0
;
;
.pg1_chk_1st_open
cmp #frstopensecclos; 2 just first
open
beq .pg1_1st_open ;
2/3 no, skip jmp if first
jmp .pg1_assume_2nd_open; 3 must
be second - to page 3 listing
.pg1_1st_open
+wait_change state,timeout ; 3(initial)/18(per
loop)/7(exit)
+read_sensor ; 4
sta state ; 3
;
; page 2 flowchart starts here
;
cmp #bothclos ; check
for 1st closed, 2nd still closed
bne .pg2_check_both_open ;
;
; 1st cycled, 2nd still closed
;
+sv_time_1_cls ;
10
+wait_change state,timeout ; 3(initial)/18(per
loop)/7(exit)
+read_sensor ; 4
sta state ; 3
;
; has to be 2nd open, 1st closed, other is error
;
cmp #frstclossecopen ; 2
bne .pg2_fail ; 2/3
.pg2_2nd_open
+sv_time_2_opn ;
10
jmp .pg1_1st_cycled ; 3
;
; check for both open
;
.pg2_check_both_open
cmp #bothopen ; 2
bne .pg2_2nd_open_1st_cycled ;2/3
+sv_time_2_opn ;
10
jmp .pg1_both_open ;
3
.pg2_2nd_open_1st_cycled
+sv_time_1_cls ;
10
jmp .pg2_2nd_open ;
3
;
; page 2 failures go here
;
.pg2_fail
lda #err_pg2_fail
sta errortn
rts
;
; align page 3 to ensure branches don't cross page boundries
;
!align 255,0
;
; 2nd sensor recorded light, first
;
.pg1_assume_2nd_open
+wait_change state,timeout ; 3(initial)/18(per
loop)/7(exit)
+read_sensor ; 4
sta state ; 3
;
; page 3 listing starts here
;
cmp #bothclos ; check
for 2nd closed, 1st still closed
bne .pg3_check_both_open ;
;
; 2nd cycled, 1st still closed
;
+sv_time_2_cls ;
10
+wait_change state,timeout ; 3(initial)/18(per
loop)/7(exit)
+read_sensor ; 4
sta state ; 3
;
; has to be 1st open, 2nd closed, other is error
;
cmp #frstopensecclos ; 2
bne .pg3_fail ; 2/3
.pg3_1st_open
+sv_time_1_opn ;
10
jmp .pg1_2nd_cycled ; 3
;
; check for both open
;
.pg3_check_both_open
cmp #bothopen ; 2
bne .pg3_1st_open_2nd_cycled ;2/3
+sv_time_1_opn ;
10
jmp .pg1_both_open ;
3
.pg3_1st_open_2nd_cycled
+sv_time_2_cls ;
10
jmp .pg3_1st_open ;
3
;
; page 3 failures go here
;
.pg3_fail
lda #err_pg2_fail
sta errortn
rts
;
; timeout with both shutters open, inc extended time and continue, in not
wrappedu
;
t12_timeout
inc esfrstcls ; 4
inc 1st extended close
beq timeout
; 2, timeout, exitt
inc esseccls ; 4
inc 2st extended close
beq timeout
; 2 timeout, exitt
jmp .pg1_both_open ; 3 continue
;
; timeout with only frst shutter open
;
t2_timeout
inc esseccls ; 4
inc 1st extended close
beq timeout
; 2 timeout, exit
jmp .pg1_1st_cycled ;
3 continue
;
; timeout with only second shutter open
;
t1_timeout
inc esfrstcls ; 4
inc 2nd extended close
beq timeout
; 2, timeout, exit
jmp .pg1_2nd_cycled ; 3 continue
;
; clock wrapped
;
timeout
lda #err_timeout
sta errortn
rts