-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathabn6507rom.s
executable file
·941 lines (825 loc) · 19.8 KB
/
abn6507rom.s
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
; Written by Anders Nielsen, 2023-2024
; License: https://creativecommons.org/licenses/by-nc/4.0/legalcode
.feature string_escapes ; Allow c-style string escapes when using ca65
.feature org_per_seg
.feature c_comments
;assembleprogrammer = YES
assemblelarus = 1
BAUDRATE=9600 ; Max 9600
BAUDSTEP=9600 / BAUDRATE - 1; Must be an integer
RIOT = $80
DRA = RIOT + $00 ;DRA ('A' side data register)
DDRA = RIOT + $01 ;DDRA ('A' side data direction register)
DRB = RIOT + $02 ;DRB ('B' side data register)
DDRB = RIOT + $03 ;('B' side data direction register)
READTDI = RIOT + $04 ;Read timer (disable interrupt)
WEDGC = RIOT + $04 ;Write edge-detect control (negative edge-detect,disable interrupt)
RRIFR = RIOT + $05 ;Read interrupt flag register (bit 7 = timer, bit 6 PA7 edge-detect) Clear PA7 flag
A7PEDI = RIOT + $05 ;Write edge-detect control (positive edge-detect,disable interrupt)
A7NEEI = RIOT + $06 ;Write edge-detect control (negative edge-detect, enable interrupt)
A7PEEI = RIOT + $07 ;Write edge-detect control (positive edge-detect enable interrupt)
READTEI = RIOT + $0C ;Read timer (enable interrupt)
WTD1DI = RIOT + $14 ; Write timer (divide by 1, disable interrupt)
WTD8DI = RIOT + $15 ;Write timer (divide by 8, disable interrupt)
WTD64DI = RIOT + $16 ;Write timer (divide by 64, disable interrupt)
WTD1KDI = RIOT + $17 ;Write timer (divide by 1024, disable interrupt)
WTD1EI = RIOT + $1C ;Write timer (divide by 1, enable interrupt)
WTD8EI = RIOT + $1D ;Write timer (divide by 8, enable interrupt)
WTD64EI = RIOT + $1E ;Write timer (divide by 64, enable interrupt)
WTD1KEI = RIOT + $1F ;Write timer (divide by 1024, enable interrupt)
; Bitmasks for setting and clearing signals in Data Register B (DRB) (as hex)
BITMASK_RLSBLE = $04
BITMASK_RMSBLE = $08
BITMASK_ROM_OE = $10
BITMASK_CTRL_LE = $20
BITMASK_ROM_CE = $80
; Bitmasks for additional signals (as binary)
BITMASK_VPE_TO_VPP = %00000001
BITMASK_A9_VPP_ENABLE = %00000010
BITMASK_VPE_ENABLE = %00000100
BITMASK_P1_VPP_ENABLE = %00001000
BITMASK_REG_DISABLE = %10000000
.include "macros.s"
;includes the "print" macro for printing strings
.segment "ZEROPAGE"
I2CADDR: .res 1 ; Reserve 1 byte for I2CADDR
inb: .res 1 ; Reserve 1 byte for inb - Used for Serial and I2C
outb: .res 1 ; Reserve 1 byte for outb - Used for Serial and I2C
xtmp: .res 1 ; Reserve 1 byte for xtmp
stringp: .res 2 ; Reserve 2 bytes for stringp (stringp + 1)
;Stringp +1 free for temp.
mode: .res 1 ; Reserve 1 byte for mode
rxcnt: .res 1 ; Reserve 1 byte for rxcnt
txcnt: .res 1 ; Reserve 1 byte for txcnt
runpnt: .res 2 ; Reserve 2 bytes for runpnt
cursor: .res 1 ; Reserve 1 byte for cursor ; SSD1306
scroll: .res 1 ; Reserve 1 byte for scroll ; SSD1306
tflags: .res 1 ; Reserve 1 byte for tflags ; SSD1306
serialbuf: .res 0 ; Reserve 1 byte for serialbuf - Used for text display and userland program storage
timer2 = stringp ; We're not going to be printing strings while waiting for timer2
buffer_length = cursor ; This is fine... Maybe
romaddr = runpnt
fifobufferpnt = rxcnt ; Means it'll be overwritten when we receive a command.
longdelay = txcnt
;ROM profile definition
VPP_PIN_MSK = 1 ; 0 == OE/VPP, 1 == Pin 1
VPP_DROP_MSK = 2 ; 0 == Dont drop, 1 == Drop the regulator voltage for programming and ID
ID_A9_VPP_MSK = 4 ; 0 == VPP = VPP during ID, 1 == VPP = VCC during ID
IDROM = 8 ; 0 == Doesn't support ID, 1 == Supports ID
RES2 = 16
RES3 = 32
RES4 = 64 ;
RES5 = 128
.SEGMENT "USERLAND"
.org $0e ; Just to make listing.txt match
userland:
jsr ssd1306_clear
print notinromstr
print modeenabled
;lda #0
;sta xtmp
;jmp stepperdriver
;Jump to selection
;jsr identifyrom
;jsr checkblank
/*
; This snippet just twiddles LED's
; Set DDRA to $FF to configure port A as output
lda #$FF
sta DDRA
; Initialize stringp to 1 to represent the pattern of LED lights
lda #1
sta stringp
; Loop to continuously twiddle the LED pattern
twiddle:
; Rotate left the LED pattern stored in stringp
lda stringp
rol
sta stringp
; Activate the LEDs according to the pattern
jsr latchctrl ; Control the LEDs connected to the control register
lda stringp
jsr latchmsb ; Control the LEDs connected to the MSB register
lda stringp
jsr latchlsb ; Control the LEDs connected to the LSB register
; Introduce a delay to slow down the LED pattern change
jsr delay_long
jsr delay_long
; Jump back to the beginning of the loop
jmp twiddle
*/
;This snippet will clone what's on the internal ROM to a w27c512 in less than two seconds
;jsr clonetow27c512 ; Clone and verify (print to SSD1306)
;jmp halt
;This snippit checks if ROM is identical to ROM in programmer
/*
lda #%01000000 ; Indicator
jsr latchctrl
print verifying
jsr clonecheck ; Verify
lda #%01000000
jsr latchctrl
;print romnotblankstr
lda #'$'
jsr ssd1306_sendchar
lda romaddr+1
jsr printbyte ; Print address of first mismatch ($1000 if OK)
lda romaddr
jsr printbyte
print bytesverifiedstr
jmp halt ; Back to main
*/
/*
lda #$FA
ldy #10
ldx #0
jsr writerom
*/
; This snippet programs ROM contents to a 2732 ROM (if VPE is jumpered correctly on the back of the board and VPE calibrated to 21V )
/*print cloning
lda #50
sta longdelay ; Must be initialized to either 0 for 100us ROMs or number of ms for slow programming Roms
LDA #BITMASK_REG_DISABLE | BITMASK_P1_VPP_ENABLE
JSR latchctrl ; Latch the updated control signals
;Let's make absolutely sure the regulator is stable
lda #$ff
sta DDRA
jsr delay_long ; ~256ms
lda #$ff
jsr delay_long ; ~256ms
lda #$ff
jsr delay_long ; ~256ms
;jsr clonerom2 ; Write 65uino ROM
*/
halt:
lda #$02 ; Bit 1 is serial TX (Output)
sta DDRA
;sty mode
jmp main ; Get ready for new code
fifobuffer:
.res 4
.segment "RODATA"
.org $1000 ; Start address for code (for clarity, not strictly needed)
nmi:
irq:
reset:
cld ; Clear decimal mode flag
sei ; Disable interrupts (may not be necessary with 6507)
; Set stack pointer and clear zero page RAM
ldx #$7f ; Load X register with 127 (stack starts from top of memory)
txs ; Transfer X to stack pointer
lda #0 ; Clear accumulator
bit DRB
bvc waithere ; Skip clearing RAM if USR btn held down during reset
clearzp:
sta $00,x ; Clear zero page RAM from $007F to $0000
dex ; Decrement counter
bne clearzp ; Continue clearing until every bit of RAM is clear
.ifdef runprogrammer ; Only need this if using the Relatively Universal ROM Programmer
JSR latchctrl ; Call latchctrl subroutine to latch 0 into control register
.endif
lda #%01010000 ; Initialize DRB with bit 4 and 6 set to 1, rest to 0
sta DRB
lda #%10111100 ; Set B register direction: Bit 0, 1 are SCL and SDA, bit 6 is input button
sta DDRB
lda #%11111011 ; Set A register default -
sta DRA
lda #$02 ; Set bit 1 of DDRA for serial TX (Output)
sta DDRA
lda #244
jsr delay_long ; Delay for a short time
lda #$3C ; Address of the device (78 on the back of the module is 3C << 1)
sta I2CADDR
jsr ssd1306_init ; Initialize SSD1306 display
lda #244
jsr delay_long ; Delay for a short time
jsr ssd1306_clear ; Clear display
; Main routine for controlling LED and handling button press
;Fall through
jmp mainmenu
gomenu:
jmp selectormove
waithere:
bit DRB
bvc waithere ; Stay here until USR released
main:
bit DRB ; Check the status of DRB (Data Register B)
bvc gomenu ;Button pressed, cancel this and go update menu
bpl ledoff ; If DRB is clear (LED on), branch to ledoff to turn it off
lda DRB ; Load DRB (LED off)
and #$7f ; Clear bit 7 to turn the LED on
sta DRB ; Store the modified value back to DRB
jmp l71 ; Jump to l71 to continue execution
ledoff:
lda DRB ; Load DRB (LED on)
ora #$80 ; Set bit 7 to turn the LED off
sta DRB ; Store the modified value back to DRB
l71:
lda #244 ; Load accumulator with value 244 (approx. 16ms delay)
bit DRB ; Check the status of DRB
bvs quartersecond ; Button isn't pressed branch to quartersecond
jmp selectormove ; Button pressed, change main menu selection
quartersecond:
sta WTD1KDI ; Set timer for approximately quarter of a second (244 * 1024 ≈ 249856 cycles)
bne wait ; Branch (BRA - Branch Always)
gonoserial:
jmp noserial
wait:
bit DRB
bvc gomenu
lda DRA ; Check serial 3c
/* Flow control disabled
and #%11111011 ; CTS low
sta DRA
*/
and #$01 ; 2c
bne gonoserial ; 2c
tay ; A already 0
sta txcnt
lda #64 ; RX wait loop below is 16 cycles
sta timer2
rx:
dec timer2
beq rxtimeout ; Branch if timeout
lda DRA ; Check serial 3c
and #$01 ; 2c
bne rx ; Wait for RX until timeout
lda #64
sta timer2 ; Reset timer
gorx:
jsr serial_rx ; 6c
sta serialbuf, y
cpy #128-(<userland)-9 ; Leaves 9 bytes for stack
beq rx_err
iny
bne rx ; BRA (Y never 0)
rx_err:
sty rxcnt
/* Flow control disabled
lda DRA ;
ora #4 ; CTS high
sta DRA
lda #$13 ; XOFF
jsr serial_tx ; Inform sender we're out of buffer space
*/
lda #<overflow
sta stringp
lda #>overflow
sta stringp+1
jsr ssd1306_wstring
clc
bcc tx ; BRA
rxtimeout:
sty rxcnt
lda mode
beq txt
cmp #1
beq bootload
.ifdef runprogrammer
cmp #2
beq programmer
.endif
bootload:
;Time to parse data instead of txt - aka, our bootloader!
jsr ssd1306_clear
lda #<loaded
sta stringp
lda #>loaded
sta stringp+1
jsr ssd1306_wstring
lda rxcnt
jsr printbyte
lda #<bytes
sta stringp
lda #>bytes
sta stringp+1
jsr ssd1306_wstring
waittorun:
lda #250
jsr delay_long
jsr ssd1306_clear
jmp userland
.ifdef runprogrammer
programmer:
JMP runprogrammer
.endif
txt:
/* Flow control disabled
lda DRA ;
ora #4 ; CTS high
sta DRA
lda #$13 ; XOFF
jsr serial_tx ; Inform sender to chill while we write stuff to screen
*/
tx:
ldy txcnt ;Check if this is the first byte of the frame
bne notfirst
lda serialbuf, y ;If it is, we check if it's a command (not ascii)
cmp #$01 ; SOH
beq boot
cmp #$AA
.ifdef runprogrammer
beq programmer
.endif
bne notfirst
boot:
sta mode
jmp main ; Bootloader character via serial
notfirst:
cpy rxcnt
beq txdone
lda serialbuf, y
jsr ssd1306_sendchar
inc txcnt
jmp tx
noserial:
lda READTDI
bne gowait ; Loop until timer runs out
jmp main ; loop
txdone:
/* Flow control disabled
lda DRA ;
and #$fb ; CTS low
sta DRA
lda #$11 ; XON
jsr serial_tx
*/
gowait:
jmp wait
stepperdriver:
lda #10
sta mode
lda #$0C ; Set bits 2 and 3 as outputs
sta DDRA
; Initialize direction (default to clockwise, bit 3 = 0)
lda #$08
sta xtmp
more:
; Check button press (DRB bit 6 = low)
bit DRB ; Load DRB register
bvs noleft ; Skip if bit 6 is high (button not pressed)
lda #8
sta xtmp
noleft:
bit DRA
bvs no_change
; Toggle direction
lda #0
sta xtmp
no_change:
ldx #20
spin:
lda xtmp ; Load the direction from xtmp
ora #$04 ; Combine with step (bit 2)
sta DRA ; Write to DRA (step + direction)
lda #15 ; 500uS delay
jsr delay_short
lda xtmp ; Load direction again (to clear step while keeping direction)
sta DRA ; Clear step (only direction bit remains)
lda #10
jsr delay_short
dex
bne spin
lda mode
jsr delay_long
jmp more
.ifdef assemblelarus
.include "flappylarus.s" ; Flappy Larus game routines
.endif
.include "i2c.s" ; i2c rutines specifically for the 65uino. Provides i2c_start, i2cbyteout, i2cbytein, i2c_stop - expects a few
.include "ssd1306.s" ; SSD1306 routines specifically for the 65uino. Provides ssd1306_init, ssd1306_clear, ssd1306_sendchar, ssd1306_setline, ssd1306_cmd, ssd1306_wstring, printbyte
.ifdef assembleprogrammer
.include "programmer.s" ; ; Relatively Universal ROM Programmer 6502 Firmware
.endif
ready:.asciiz "Ready to load code... "
loading:.asciiz "Loading... "
overflow:.asciiz "OF!"
loaded: .asciiz "Loaded "
bytes: .asciiz " bytes of data."
modeenabled: .asciiz " enabled. Press RST to exit."
notinromstr: .asciiz "Code not in rom / not"
welcome:
;.asciiz "Hi! I'm the 65uino! I'm a 6502 baseddev board. Come learn everything about me!"
;.word $0000
flappylarusstr: .asciiz "Flappy Larus" ;0
userlandstr: .asciiz "Run Userland $0E" ;1
codemonstr: .asciiz "Code Monitor" ;2
i2cscannerstr: .asciiz "I2C Scanner" ;3
terminalstr: .asciiz "Terminal" ;4
.ifdef runprogrammer
idromstr: .asciiz "Check ROM ID" ;4
eraseromstr: .asciiz "Erase ROM" ;5
blankcheckromstr: .asciiz "Blank check IC" ;6
.endif
airplanestr: .asciiz "Airplane mode" ;7
stepperstr: .asciiz "Stepper motor ctrl"
longpress:
jsr ssd1306_clear
lda itemsel
beq startflappylarus
cmp #1
beq gouserland
cmp #2
beq gomon
cmp #3
beq notinrom ; I2C scanner not written yet
cmp #4
bne l477
jsr ssd1306_clear ; Clear screen to get ready for serial data
lda #0
sta mode
jmp wait
l477:
.ifdef runprogrammer
cmp #5
beq startidentifyrom
cmp #6
beq starteraserom
cmp #7
beq startblankcheck
.endif
cmp #8
beq airplanemode
cmp #9
jmp stepperdriver
gouserland:
jmp userland
gomon:
jsr monitor
jmp main
startflappylarus:
.ifdef flappylarus
jsr flappylarus
.else
jmp notinrom
.endif
sec
bcs pausehere
.ifdef runprogrammer
startblankcheck:
jsr blankcheck
sec
bcs pausehere
starteraserom:
jsr flappylarus
sec
bcs pausehere
startidentifyrom:
jsr identifyrom
;fall to pause
.endif
pausehere:
lda #100
jsr delay_long ; Pause long enough that user probably has released button
actuallyhere:
bit DRB
bvs actuallyhere ; Button released
jmp main
airplanemode:
print airplanestr
print modeenabled
.byte $F2 ; JAM - locks up CPU, preventing more instructions from loading
notinrom:
print notinromstr
print modeenabled
jmp pausehere
menutable:
.word flappylarusstr
.word userlandstr
.word codemonstr
.word i2cscannerstr
.word terminalstr
.ifdef runprogrammer
.word idromstr
.word eraseromstr
.word blankcheckromstr
.endif
.word airplanestr
.word stepperstr
.word $0000
wait_getserial:
lda #$02 ; Set bit 1 for serial TX (Output), clear bit 0 for serial RX (Input)
sta DDRA ; Store to configure port direction
wait_getserial2:
lda DRA ; Check serial 3c
and #$01 ; 2c
bne wait_getserial2 ; 2c
jsr serial_rx ; Get character
rts
; jsr = 6 cycles
; sta (zp) = 3 cycles
; (WTD8DI -1) * 8 cycles
; We can ignore branches while timer not 0
;lda (zp) = 3 cycles
; bne = 2 cycles (not taken since timer expired)
; rts = 6 cycles
; = 20 + ((WTD8DI - 1) * 8) cycles
delay_short:
sta WTD8DI ; Divide by 8 = A contains ticks to delay/8
shortwait:
nop; Sample every 8 cycles instead of every 6
lda READTDI
bne shortwait
rts
delay_long:
sta WTD1KDI
wait1k:
lda READTDI
bne wait1k ; Loop until timer runs out
rts
;Returns byte in A - assumes 9600 baud = ~104us/bit, 1 cycle = 1us (1 MHz)
;We should call this ASAP when RX pin goes low - let's assume it just happened (13 cycles ago)
serial_rx:
;Minimum 13 cycles before we get here
lda #(15+19*BAUDSTEP) ; 1.5 period-ish ; 2 cycles - 15 for 9600 baud, 34 for 4800
jsr delay_short ; 140c
ldx #8 ; 2 cycles
;149 cycles to get here
serial_rx_loop: ;103 cycles
lda DRA ; Read RX bit 0 ; 3 cycles
lsr ; Shift received bit into carry - in many cases might be safe to just lsr DRA ; 2 cycles
ror inb ; Rotate into MSB 5 cycles
lda #(9+13*BAUDSTEP) ; 2 cycles ;9 for 9600 baud, 22 for 4800 baud (add 104us == 104 / 8 = 13)
jsr delay_short ; Delay until middle of next bit - overhead; 84 cycles
nop ; 2c
dex ; 2c
bne serial_rx_loop ; 3 cycles
;Should already be in the middle of the stop bit
; We can ignore the actual stop bit and use the time for other things
; Received byte in inb
lda inb ; Put in A
rts
serial_tx:
sta outb
lda #$fd ; Inverse bit 1
and DRA
sta DRA ; Start bit
lda #(8+13*BAUDSTEP) ; 2c ; 9600 = 8, 4800 = 21
jsr delay_short ; 20 + (8-1)*8 = 76c ; Start bit total 104 cycles - 104 cycles measured
nop ; 2c
nop ; 2c
ldx #8 ; 2c
serial_tx_loop:
lsr outb ; 5c
lda DRA ; 3c
bcc tx0 ; 2/3c
ora #2 ; TX bit is bit 1 ; 2c
bcs bitset ; BRA 3c
tx0:
nop ; 2c
and #$fd ; 2c
bitset:
sta DRA ; 3c
; Delay one period - overhead ; 101c total ; 103c measured
lda #(8+13*BAUDSTEP) ; 2c ; 9600 8, 4800 21
jsr delay_short ; 20 + (8-1)*8 = 76c
nop; 2c fix
dex ; 2c
bne serial_tx_loop ; 3c
nop; 2c ; Last bit 98us counted, 100us measured
nop; 2c
nop; 2c
nop; 2c
lda DRA ;3c
ora #2 ; 2c
sta DRA ; Stop bit 3c
lda #(8+13*BAUDSTEP) ; 2c ; 9600 8, 4800 21
jsr delay_short
rts
serial_wstring:
ldy #0
txstringloop:
lda (stringp),y
beq stringtxd
jsr serial_tx
iny
bne txstringloop
stringtxd:
rts ; In case of overflow
bytetoa: ;This SR puts LSB in A and MSB in HXH - as ascii using hextoa.
pha
lsr
lsr
lsr
lsr
clc
jsr hextoa
sta xtmp
pla
and #$0F
jsr hextoa
rts
hextoa:
; wozmon-style
; and #%00001111 ; Mask LSD for hex print.
; Already masked when we get here.
ora #'0' ; Add '0'.
cmp #'9'+1 ; Is it a decimal digit?
bcc ascr ; Yes, output it.
adc #$06 ; Add offset for letter.
ascr:
rts
mainmenu:
itemsel = txcnt
lda #8
sta itemsel
bne shortpress ; BRA
gomain:
jmp main
debouncebtn:
;If button is pressed
lda #$ff
sta WTD1KDI
waitbounce:
lda READTDI
beq btntimeout
bit DRB
bvs short ; Button released before timeout
bvc waitbounce ; BRA - Loop until timer runs out.
btntimeout:
sec
rts
short:
clc
rts
selectormove:
jsr debouncebtn
bcc shortpress
golongpress:
jmp longpress
menuitem = rxcnt
shortpress: ; Notice! Not a subroutine!
;Increment selection
inc itemsel
reloop:
ldx #0
stx cursor
menuloop:
stx menuitem
txa
lsr ; Divide by two to convert pointer index to line number
jsr ssd1306_setline
lda #0
jsr ssd1306_zerocolumn
ldx menuitem
lda menutable, X ; Grab item pointer L
bne notprinted
sta stringp
lda menutable+1,X ; Grab item pointer H
beq printedmenu
sta stringp+1
bne l693 ; BRA
notprinted:
sta stringp
lda menutable+1,X ; Grab item pointer H
sta stringp+1
l693:
txa
lsr ; Convert index counter to item number
cmp itemsel
beq selected
lda tflags
and #$7f
sta tflags ; Invert off
clc
bcc notselected; BRA
selected:
lda tflags
ora #$C0 ; Invert text and fast
sta tflags
notselected:
jsr ssd1306_wstring
ldx menuitem ; Restore
inx
inx
bne menuloop ; BRA
printedmenu:
txa
lsr ; Convert index to item number
sec
sbc #1
cmp itemsel
bcs notlastitem ; Selected item over number of items
lda #0
sta itemsel
beq reloop
notlastitem:
lda #0
sta mode
jmp main ; Release control
monitor:
selectedbyte = txcnt
lastnewpage = rxcnt
jsr ssd1306_clear
lda #$40
sta tflags
tya
sta lastnewpage
sta selectedbyte
sta runpnt+1
newscreen:
sta runpnt
nextline:
jsr setcursor
lda #'$'
jsr ssd1306_sendchar
lda runpnt
jsr printbyte
lda #':'
jsr ssd1306_sendchar
printram:
inc cursor ; Space
jsr setcursor
jsr checkline
lda (runpnt),Y
pha
lda runpnt
cmp selectedbyte
bne notit
lda tflags
ora #$C0 ; Invert
bne it ; BRA
notit:
lda #$42 ; Leave selection and fast bit
and tflags
it:
sta tflags
pla
jsr printbyte
;;; If selected, we loop here
lda tflags
and #2 ; Selected flag
beq unselect
lda runpnt
cmp selectedbyte
bne afterunselect
changevalue:
bit DRB
bvs changevalue ; Wait for button press
jsr debouncebtn ; Short or long?
bcs startover
;Go back two cursor positions
dec cursor
dec cursor
jsr setcursor
inc stringp ; Borrow this for tmp
lda (runpnt),Y
adc stringp
jsr printbyte
jmp changevalue ; BRA
startover:
lda (runpnt),Y
clc
adc stringp
sta (runpnt),Y
tya ; 0
sta stringp
jsr ssd1306_clear
lda lastnewpage
jmp newscreen
;;;
unselect:
lda #$40 ; Clear inversion and selection
sta tflags
afterunselect:
lda runpnt
adc #1
sta runpnt
and #$03
bne printram
lda cursor
bne nextline
l122:
bit DRB
bvs l122
jsr debouncebtn
bcc nextitem
bcs selectitem
;Select current item
nextitem:
lda selectedbyte
adc #1
sta selectedbyte
and #$1f ; Check for rollover to next page
beq nextpage ; Selected above range, move range
lda lastnewpage
bcc gnewscreen ; BRA
nextpage:
lda lastnewpage
adc #$20 ; One page+
sta lastnewpage
bne gnewscreen ; BRA
selectitem:
lda #2
ora tflags
sta tflags
l877:
bit DRB
bvc l877
gnewscreen:
lda lastnewpage
jmp newscreen ; BRA
.segment "VECTORS6502"
.ORG $1ffa
.word nmi,reset,irq
.reloc