-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathfirmware.asm
More file actions
2036 lines (1723 loc) · 65.7 KB
/
firmware.asm
File metadata and controls
2036 lines (1723 loc) · 65.7 KB
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
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
;===============================================================================
; ____ ____ __ ____ ___ ____
; / ___|| __ ) / /_| ___| / _ \___ \
; \___ \| _ \ _____| '_ \___ \| | | |__) |
; ___) | |_) |_____| (_) |__) | |_| / __/
; |____/|____/ \___/____/ \___/_____|
;
; A Firmware for a Three Chip 6502/65C02/65SC02/65C802 Single Board Computer
;-------------------------------------------------------------------------------
; Copyright (C)2014-2020 Andrew John Jacobs
; All rights reserved.
;
; This work is made available under the terms of the Creative Commons
; Attribution-NonCommercial-ShareAlike 4.0 International license. Open the
; following URL to see the details.
;
; http://creativecommons.org/licenses/by-nc-sa/4.0/
;===============================================================================
;
; Notes:
;
; This firmware programs a Microchip PIC18F microcontroller to act as the glue
; logic between a Rockwell/Synertec 6502 or WDC 65C02 and 64K of a 128K SRAM
; memory chip while partially emulating a 6551 ACIA, a 65SPI interface and a
; DS1813 RTC.
;
; At start up the firmware determines which microprocessor is installed by
; executing a JMP ($00FF) instruction and checking which memory locations the
; indirect address is read from (e.g. $00FF/$0000 = 6502, $00FF/$0100 = 65C02
; & 65C802) and the number of cycles taken to do it. Further instructions are
; executed if a 65C02 is found to determine if it is a 65SC02. A different boot
; ROM image is loaded for each type of device.
;
; FOSC is too fast for the UART to be set to 50 or 75 baud. The other speeds
; should work.
;-------------------------------------------------------------------------------
#define M(X) (.1 << (X))
;===============================================================================
; Fuse Settings
;-------------------------------------------------------------------------------
ifdef __18F46K22
include "P18F46K22.inc"
config FOSC=INTIO67,PLLCFG=ON,PRICLKEN=ON,FCMEN=OFF,IESO=OFF
config BOREN=OFF,WDTPS=1024,STVREN=ON,LVP=OFF,XINST=OFF
config CCP2MX=PORTC1,PBADEN=OFF,HFOFST=ON,MCLRE=EXTMCLR
ifdef __DEBUG
config WDTEN=OFF,DEBUG=ON,PWRTEN=OFF
else
config WDTEN=OFF,DEBUG=OFF,PWRTEN=ON
endif
config CP0=OFF,CP1=OFF,CP2=OFF,CP3=OFF,CPB=OFF,CPD=OFF
config WRT0=OFF,WRT1=OFF,WRT2=OFF,WRT3=OFF,WRTC=OFF,WRTB=OFF,WRTD=OFF
config EBTR0=OFF,EBTR1=OFF,EBTR2=OFF,EBTR3=OFF
config EBTRB=OFF
OSC equ .16000000
PLL equ .4
endif
;-------------------------------------------------------------------------------
ifdef __18F47K40
include "P18F47K40.inc"
; CONFIG1L
CONFIG FEXTOSC = OFF ; External Oscillator mode Selection bits (Oscillator not enabled)
CONFIG RSTOSC = HFINTOSC_64MHZ; Power-up default value for COSC bits (HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:1)
; CONFIG1H
CONFIG CLKOUTEN = OFF ; Clock Out Enable bit (CLKOUT function is disabled)
CONFIG CSWEN = OFF ; Clock Switch Enable bit (The NOSC and NDIV bits cannot be changed by user software)
CONFIG FCMEN = OFF ; Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)
; CONFIG2L
CONFIG MCLRE = EXTMCLR ; Master Clear Enable bit (If LVP = 0, MCLR pin is MCLR; If LVP = 1, RE3 pin function is MCLR )
ifdef __DEBUG
CONFIG PWRTE = OFF ; Power-up Timer Enable bit (Power up timer disabled)
else
CONFIG PWRTE = ON ; Power-up Timer Enable bit (Power up timer enabled)
endif
CONFIG LPBOREN = OFF ; Low-power BOR enable bit (ULPBOR disabled)
CONFIG BOREN = OFF ; Brown-out Reset Enable bits (Brown-out Reset disabled)
; CONFIG2H
CONFIG BORV = VBOR_2P45 ; Brown Out Reset Voltage selection bits (Brown-out Reset Voltage (VBOR) set to 2.45V)
CONFIG ZCD = OFF ; ZCD Disable bit (ZCD disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCON)
CONFIG PPS1WAY = ON ; PPSLOCK bit One-Way Set Enable bit (PPSLOCK bit can be cleared and set only once; PPS registers remain locked after one clear/set cycle)
CONFIG STVREN = ON ; Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
CONFIG DEBUG = OFF ; Debugger Enable bit (Background debugger disabled)
CONFIG XINST = OFF ; Extended Instruction Set Enable bit (Extended Instruction Set and Indexed Addressing Mode disabled)
; CONFIG3L
CONFIG WDTCPS = WDTCPS_31 ; WDT Period Select bits (Divider ratio 1:65536; software control of WDTPS)
CONFIG WDTE = OFF ; WDT operating mode (WDT Disabled)
; CONFIG3H
CONFIG WDTCWS = WDTCWS_7 ; WDT Window Select bits (window always open (100%); software control; keyed access not required)
CONFIG WDTCCS = SC ; WDT input clock selector (Software Control)
; CONFIG4L
CONFIG WRT0 = OFF ; Write Protection Block 0 (Block 0 (000800-003FFFh) not write-protected)
CONFIG WRT1 = OFF ; Write Protection Block 1 (Block 1 (004000-007FFFh) not write-protected)
CONFIG WRT2 = OFF ; Write Protection Block 2 (Block 2 (008000-00BFFFh) not write-protected)
CONFIG WRT3 = OFF ; Write Protection Block 3 (Block 3 (00C000-00FFFFh) not write-protected)
CONFIG WRT4 = OFF ; Write Protection Block 3 (Block 4 (010000-013FFFh) not write-protected)
CONFIG WRT5 = OFF ; Write Protection Block 3 (Block 5 (014000-017FFFh) not write-protected)
CONFIG WRT6 = OFF ; Write Protection Block 3 (Block 6 (018000-01BFFFh) not write-protected)
CONFIG WRT7 = OFF ; Write Protection Block 3 (Block 7 (01C000-01FFFFh) not write-protected)
; CONFIG4H
CONFIG WRTC = OFF ; Configuration Register Write Protection bit (Configuration registers (300000-30000Bh) not write-protected)
CONFIG WRTB = OFF ; Boot Block Write Protection bit (Boot Block (000000-0007FFh) not write-protected)
CONFIG WRTD = OFF ; Data EEPROM Write Protection bit (Data EEPROM not write-protected)
CONFIG SCANE = OFF ; Scanner Enable bit (Scanner module is NOT available for use, SCANMD bit is ignored)
CONFIG LVP = OFF ; Low Voltage Programming Enable bit (HV on MCLR/VPP must be used for programming)
; CONFIG5L
CONFIG CP = OFF ; UserNVM Program Memory Code Protection bit (UserNVM code protection disabled)
CONFIG CPD = OFF ; DataNVM Memory Code Protection bit (DataNVM code protection disabled)
; CONFIG5H
; CONFIG6L
CONFIG EBTR0 = OFF ; Table Read Protection Block 0 (Block 0 (000800-003FFFh) not protected from table reads executed in other blocks)
CONFIG EBTR1 = OFF ; Table Read Protection Block 1 (Block 1 (004000-007FFFh) not protected from table reads executed in other blocks)
CONFIG EBTR2 = OFF ; Table Read Protection Block 2 (Block 2 (008000-00BFFFh) not protected from table reads executed in other blocks)
CONFIG EBTR3 = OFF ; Table Read Protection Block 3 (Block 3 (00C000-00FFFFh) not protected from table reads executed in other blocks)
CONFIG EBTR4 = OFF ; Table Read Protection Block 4 (Block 4 (010000-013FFFh) not protected from table reads executed in other blocks)
CONFIG EBTR5 = OFF ; Table Read Protection Block 5 (Block 5 (014000-017FFFh) not protected from table reads executed in other blocks)
CONFIG EBTR6 = OFF ; Table Read Protection Block 6 (Block 6 (018000-01BFFFh) not protected from table reads executed in other blocks)
CONFIG EBTR7 = OFF ; Table Read Protection Block 7 (Block 7 (01C000-01FFFFh) not protected from table reads executed in other blocks)
; CONFIG6H
CONFIG EBTRB = OFF ; Boot Block Table Read Protection bit (Boot Block (000000-0007FFh) not protected from table reads executed in other blocks)
OSC equ .64000000
PLL equ .1
endif
;-------------------------------------------------------------------------------
ifdef __DEBUG
CYCLE_DEBUG equ 0 ; 1 if debugging at cycle level
ADRH_MASK equ h'3f' ; 3f when ICSP is enabled
else
CYCLE_DEBUG equ 0 ; 1 if debugging at cycle level
ADRH_MASK equ h'ff' ; ff when PORTB is full byte
endif
;===============================================================================
; Debugging Macros
;-------------------------------------------------------------------------------
TRACE_NEWL macro
if CYCLE_DEBUG
rcall NewLine
endif
endm
TRACE_ADDR macro
if CYCLE_DEBUG
rcall ShowAddr
endif
endm
TRACE_DATA macro
if CYCLE_DEBUG
rcall ShowData
endif
endm
;===============================================================================
; Constants
;-------------------------------------------------------------------------------
BOOT_ADDR equ h'1000' ; Dummy reset address
ROM_BASE equ h'c000' ; Base address of ROM image
; ASCII Control Characters
LF equ .10
CR equ .13
;===============================================================================
; Device Configuration
;-------------------------------------------------------------------------------
; Internal Oscillator
FOSC equ OSC * PLL
; 6502/65C02 Control Pins
ADRL_TRIS equ TRISA
ADRL_PORT equ PORTA
ADRL_LAT equ LATA
ADRH_TRIS equ TRISB
ADRH_PORT equ PORTB
ADRH_LAT equ LATB
DATA_TRIS equ TRISD
DATA_PORT equ PORTD
DATA_LAT equ LATD
NRAM_TRIS equ TRISC
NRAM_LAT equ LATC
NRAM_PIN equ .0
NIRQ_TRIS equ TRISC
NIRQ_LAT equ LATC
NIRQ_PIN equ .1
NRES_TRIS equ TRISE
NRES_LAT equ LATE
NRES_PIN equ .0
PHI0_TRIS equ TRISE
PHI0_LAT equ LATE
PHI0_PIN equ .1
RW_TRIS equ TRISE
RW_PORT equ PORTE
RW_PIN equ .2
; UART Signal Pins
TXD_TRIS equ TRISC
TXD_PIN equ .6
RXD_TRIS equ TRISC
RXD_PIN equ .7
#define UART_BRG(X) (FOSC / (.16 * (X)) - .1)
; SPI Signal Pins
SEL_TRIS equ TRISC
SEL_PIN equ .2
SCK_TRIS equ TRISC
SCK_PIN equ .3
SDI_TRIS equ TRISC
SDI_PIN equ .4
SDO_TRIS equ TRISC
SDO_PIN equ .5
#define SPI_BRG(X) (FOSC / (.4 * (X)) - .1)
; Timer 2
TMR2_HZ equ .4096
TMR2_PRE equ .4
TMR2_POST equ .8
TMR2_PR equ FOSC / (.4 * TMR2_HZ * TMR2_PRE * TMR2_POST) - .1
if TMR2_PR & h'ffffff00'
error "Timer2 period does not fit in 8-bits"
endif
;===============================================================================
; Data Areas
;-------------------------------------------------------------------------------
udata_acs
EXTRA_CYCLE res .1 ; 'ff' if JMP (aa) is longer
CAPTURE res .1
ROML res .1 ; Base address of ROM image
ROMH res .1
ROMU res .1
ADDRL res .1 ; Address of next ROM byte to
ADDRH res .1 ; .. force load
SCRATCH res .1 ; Scratch area
;-------------------------------------------------------------------------------
INT_FLAG res .1 ; Software interrupt flags
INT_MASK res .1 ; Interrupt mask
INT_HW_RXD equ RC1IF
INT_HW_TXD equ TX1IF
INT_HW_SPI equ SSP1IF
INT_SW_TMR equ TMR2IF
ACIA_CMD res .1 ; ACIA Command Register
ACIA_CTL res .1 ; ACIA Control Register
SPI_CTL res .1 ; SPI Command Register
SPI_DIV res .1 ; SPI Divisor Register
SPI_SEL res .1 ; SPI Select Register
RTC_SUB0R res .1 ; RTC Realtime registers
RTC_SUB1R res .1
RTC_SEC0R res .1
RTC_SEC1R res .1
RTC_SEC2R res .1
RTC_SEC3R res .1
RTC_SUB0 res .1 ; RTC Buffered registers
RTC_SUB1 res .1
RTC_SEC0 res .1
RTC_SEC1 res .1
RTC_SEC2 res .1
RTC_SEC3 res .1
RTC_ALM0 res .1
RTC_ALM1 res .1
RTC_ALM2 res .1
RTC_ALM3 res .1
RTC_CTLA res .1
RTC_CTLB res .1
RTC_STAT res .1
RTC_PERIOD res .5 ; Periodic interrupt period
RTC_COUNT res .5 ; Periodic interrupt count
ROM_OFF0 res .1 ; Current offset
ROM_OFF1 res .1
ROM_LK0 res .1 ; Unlock sequence
ROM_LK1 res .1
;===============================================================================
; Reset Vector
;-------------------------------------------------------------------------------
.ResetVector code h'0000'
goto PowerOnReset
;===============================================================================
; Interrupt Handler
;-------------------------------------------------------------------------------
.Interrupt code h'0008'
ifdef __18F46K22
bcf PIR1,TMR2IF ; Clear the interrupt flag
endif
ifdef __18F47K40
bcf PIR4,TMR2IF ; Clear the interrupt flag
endif
movf RTC_CTLB,W ; Is period interrupt configured?
andlw h'f0'
bz BumpTime
incf RTC_COUNT+.0,F ; Yes, update counter
bnz BumpTime
incf RTC_COUNT+.1,F
bnz BumpTime
incf RTC_COUNT+.2,F
bnz BumpTime
incf RTC_COUNT+.3,F
bnz BumpTime
incf RTC_COUNT+.4,F
bnz BumpTime
bsf RTC_STAT,.1 ; Flag period interrupt
btfsc RTC_CTLA,.1
bsf INT_FLAG,INT_SW_TMR
movf RTC_PERIOD+.0,W ; Reset the period
movwf RTC_COUNT+.0
movf RTC_PERIOD+.1,W
movwf RTC_COUNT+.1
movf RTC_PERIOD+.2,W
movwf RTC_COUNT+.2
movf RTC_PERIOD+.3,W
movwf RTC_COUNT+.3
movf RTC_PERIOD+.4,W
movwf RTC_COUNT+.4
BumpTime:
movlw h'10' ; Bump the time value
addwf RTC_SUB0R,W
movwf RTC_SUB0R
btfsc RTC_CTLA,.7
movwf RTC_SUB0
movlw .0
addwfc RTC_SUB1R,W
movwf RTC_SUB1R
btfsc RTC_CTLA,.7
movwf RTC_SUB1
btfss STATUS,C ; Exit early if no change to
retfie FAST ; .. the seconds
movlw .0
addwfc RTC_SEC0R,W
movwf RTC_SEC0R
btfsc RTC_CTLA,.7
movwf RTC_SEC0
movlw .0
addwfc RTC_SEC1R,W
movwf RTC_SEC1R
btfsc RTC_CTLA,.7
movwf RTC_SEC1
movlw .0
addwfc RTC_SEC2R,W
movwf RTC_SEC2R
btfsc RTC_CTLA,.7
movwf RTC_SEC2
movlw .0
addwfc RTC_SEC3R,W
movwf RTC_SEC3R
btfsc RTC_CTLA,.7
movwf RTC_SEC3
movf RTC_SEC0,W ; Matched the alarm?
xorwf RTC_ALM0,W
btfss STATUS,Z
retfie FAST ; No
movf RTC_SEC1,W
xorwf RTC_ALM1,W
btfss STATUS,Z
retfie FAST ; No
movf RTC_SEC2,W
xorwf RTC_ALM2,W
btfss STATUS,Z
retfie FAST ; No
movf RTC_SEC2,W
xorwf RTC_ALM2,W
btfss STATUS,Z
retfie FAST ; Done
bsf RTC_STAT,.0 ; Flag alarm match
btfsc RTC_CTLA,.0
bsf INT_FLAG,INT_SW_TMR
retfie FAST
;===============================================================================
; Power On Reset
;-------------------------------------------------------------------------------
code
PowerOnReset:
banksel ANSELA
clrf ANSELA ; Turn analog off
clrf ANSELB
clrf ANSELC
clrf ANSELD
clrf ANSELE
clrf LATC ; Clear output latches
clrf LATE
bcf NRES_TRIS,NRES_PIN ; Pull /RES low to reset 6502
bcf NRES_LAT,NRES_PIN
bsf NIRQ_TRIS,NIRQ_PIN ; Ensure /IRQ is high
bcf NIRQ_LAT,NIRQ_PIN
bcf PHI0_TRIS,PHI0_PIN ; Make PHI0 high output
bsf PHI0_LAT,PHI0_PIN
bcf NRAM_TRIS,NRAM_PIN ; Make /RAM high output
bsf NRAM_LAT,NRAM_PIN
;-------------------------------------------------------------------------------
ifdef __18F46K22
movlw b'01110000' ; Set oscillator for 16 MIPs
movwf OSCCON
bsf OSCTUNE,PLLEN ; And enable 4x PLL
ifndef __DEBUG
WaitTillStable:
btfss OSCCON,HFIOFS ; And wait until stable
bra WaitTillStable
endif
endif
;-------------------------------------------------------------------------------
ifdef __18F47K40
banksel PPSLOCK ; Unlock PPS module
movlw h'55'
movwf PPSLOCK
movlw h'aa'
movwf PPSLOCK
bcf PPSLOCK,PPSLOCKED
movlw h'0f' ; RC3 is SCK1
movwf RC3PPS
movlw h'13'
movwf SSP1CLKPPS
movlw h'14' ; RC4 is SDI1
movwf SSP1DATPPS
movlw h'10' ; RC5 is SDO1
movwf RC5PPS
movlw h'09' ; RC6 is TX1
movwf RC6PPS
movlw h'17' ; RC7 is RX1
movwf RX1PPS
banksel PPSLOCK ; Lock PPS module
movlw h'55'
movwf PPSLOCK
movlw h'aa'
movwf PPSLOCK
bsf PPSLOCK,PPSLOCKED
endif
;-------------------------------------------------------------------------------
bcf TXD_TRIS,TXD_PIN ; Make TXD an output
bsf RXD_TRIS,RXD_PIN ; .. and RXD an input
if CYCLE_DEBUG
movlw low UART_BRG(.19200) ; F = 19200
movwf SPBRG1
movlw high UART_BRG(.19200)
movwf SPBRGH1
endif
movlw M(BRG16) ; Configure UART
movwf BAUDCON1
movlw M(TXEN)
movwf TXSTA1
movlw M(SPEN)|M(CREN)
movwf RCSTA1
movf RCREG1,W ; Clear input buffer
movf RCREG1,W
;-------------------------------------------------------------------------------
bcf SCK_TRIS,SCK_PIN ; Configure SPI pins
bcf SDO_TRIS,SDO_PIN
bsf SDI_TRIS,SDI_PIN
bcf SEL_TRIS,SEL_PIN
movlw M(SSPEN)|b'1010' ; Configure SPI
movwf SSP1CON1
movf SSP1BUF,W
movf SSP1BUF,W
;-------------------------------------------------------------------------------
movlw TMR2_PR ; Configure Timer2
movwf PR2
movlw M(TMR2ON)|((TMR2_POST-.1) << .3)|h'01'
clrf TMR2
movwf T2CON
ifdef __18F46K22
bcf PIR1,TMR2IF
endif
ifdef __18F47K40
bcf PIR4,TMR2IF
endif
bsf INTCON,PEIE
;-------------------------------------------------------------------------------
clrf EXTRA_CYCLE ; Assume a 6502 or 65C802
;===============================================================================
; Start Regular Clock Pulses
;-------------------------------------------------------------------------------
movlw .64
PulseClock:
bcf PHI0_LAT,PHI0_PIN ; Make PHI0 low
nop
nop
nop
nop
nop
nop
bsf PHI0_LAT,PHI0_PIN ; Make PHI0 high
nop
nop
nop
nop
decfsz WREG,F ; Reduce pulse count
bra PulseClock
bsf NRES_TRIS,NRES_PIN ; Release /RES line
nop
nop
nop
nop
if CYCLE_DEBUG
rcall NewLine
rcall NewLine
movlw 'R'
rcall UartTx
movlw 'e'
rcall UartTx
movlw 's'
rcall UartTx
movlw 'e'
rcall UartTx
movlw 't'
rcall UartTx
endif
;===============================================================================
; Allow device to reset
;-------------------------------------------------------------------------------
WaitForReset:
rcall LoPhase
TRACE_NEWL
bsf PHI0_LAT,PHI0_PIN ; Make PHI0 high
nop
TRACE_ADDR
movf ADRL_PORT,W ; Address is $FFFC?
xorlw h'fc'
bnz WaitForReset ; No
movf ADRH_PORT,W
xorlw h'ff' & ADRH_MASK
bnz WaitForReset ; No
btfss RW_PORT,RW_PIN ; CPU is reading?
bra WaitForReset ; No
clrf DATA_TRIS
movlw low BOOT_ADDR ; Force boot addr low
movwf DATA_LAT
nop
nop
TRACE_DATA
rcall LoPhase
TRACE_NEWL
bsf PHI0_LAT,PHI0_PIN ; Make PHI0 high
nop
TRACE_ADDR
movf ADRL_PORT,W ; Address is $FFFD?
xorlw h'fd'
bnz WaitForReset ; No
movf ADRH_PORT,W
xorlw h'ff' & ADRH_MASK
bnz WaitForReset ; No
btfss RW_PORT,RW_PIN ; CPU is reading?
bra WaitForReset ; No
clrf DATA_TRIS
movlw high BOOT_ADDR ; Force boot addr high
movwf DATA_LAT
nop
nop
TRACE_DATA
;-------------------------------------------------------------------------------
; Feed the microprocessor a JMP (%FFFF) instruction and check which addresses
; are read.
rcall LoPhase ; Send Opcode
TRACE_NEWL
TRACE_ADDR
movlw h'6c'
rcall HiPhaseLoad
TRACE_DATA
rcall LoPhase ; Send address lo byte
TRACE_NEWL
TRACE_ADDR
movlw h'ff'
rcall HiPhaseLoad
TRACE_DATA
rcall LoPhase ; Send address hi byte
TRACE_NEWL
TRACE_ADDR
movlw h'ff'
rcall HiPhaseLoad
TRACE_DATA
rcall LoPhase
TRACE_NEWL
TRACE_ADDR
movf ADRH_PORT,W ; Rereading the high byte?
xorlw h'10'
bnz NoReread
decf EXTRA_CYCLE,F ; Yes, must be a 65C02
movlw h'ff' ; Send the address hi byte
rcall HiPhaseLoad ; .. again
TRACE_DATA
rcall LoPhase ; Send lo byte of boot address
TRACE_NEWL
TRACE_ADDR
NoReread:
movlw low BOOT_ADDR
rcall HiPhaseLoad
TRACE_DATA
rcall LoPhase
TRACE_NEWL
TRACE_ADDR
movf ADRH_PORT,W ; Capture hi byte of address
movwf CAPTURE
movlw high BOOT_ADDR ; Send hi byte of boot address
rcall HiPhaseLoad
TRACE_DATA
;-------------------------------------------------------------------------------
btfsc EXTRA_CYCLE,.7 ; Determine device
ifdef __18F46K22
bra W65C02
else
bra TestSC
endif
movf CAPTURE,W
btfsc STATUS,Z
bra W65C802
bra R6502
; Execute a SMB0 $EA NOP NOP NOP and
ifdef __18F47K40
TestSC:
rcall LoPhase ; Send SMB Opcode
TRACE_NEWL
TRACE_ADDR
movlw h'87'
rcall HiPhaseLoad
TRACE_DATA
rcall LoPhase ; Send address lo byte
TRACE_NEWL
TRACE_ADDR
movlw h'ea'
rcall HiPhaseLoad
TRACE_DATA
rcall LoPhase ; A 65C02 will address zero page
TRACE_NEWL
TRACE_ADDR
movf ADRH_PORT,W ; .. so capture the address HI
movwf CAPTURE
movlw h'ea'
rcall HiPhaseLoad
TRACE_DATA
rcall LoPhase ; Send NOP as dummy data
TRACE_NEWL
TRACE_ADDR
movlw h'ea'
rcall HiPhaseLoad
TRACE_DATA
rcall LoPhase ; Send NOP as dummy data
TRACE_NEWL
TRACE_ADDR
movlw h'ea'
rcall HiPhaseLoad
TRACE_DATA
movf CAPTURE,W ; Test captured address
bz W65C02 ; $00 = W65C02
bra R65SC02 ; Otherwise R65SC02
endif
;-------------------------------------------------------------------------------
R6502:
movlw low ROM6502 ; Fix 6502 ROM address
movwf ROML
movlw high ROM6502
movwf ROMH
movlw upper ROM6502
movwf ROMU
bra StartLoad
W65C02:
movlw low ROM65C02 ; Fix 65C02 ROM address
movwf ROML
movlw high ROM65C02
movwf ROMH
movlw upper ROM65C02
movwf ROMU
bra StartLoad
W65C802:
movlw low ROM65C802 ; Fix 65C802 ROM address
movwf ROML
movlw high ROM65C802
movwf ROMH
movlw upper ROM65C802
movwf ROMU
bra StartLoad
ifdef __18F47K40
R65SC02:
movlw low ROM65SC02 ; Fix 65SC02 ROM address
movwf ROML
movlw high ROM65SC02
movwf ROMH
movlw upper ROM65SC02
movwf ROMU
bra StartLoad
endif
;-------------------------------------------------------------------------------
StartLoad:
movff ROML,TBLPTRL ; Load pointer to ROM image
movff ROMH,TBLPTRH
movff ROMU,TBLPTRU
clrf ADDRL ; Reset ROM load location
movlw high ROM_BASE
movwf ADDRH
LoadImage:
tblrd *+
rcall LoPhase ; Force LDA #data
TRACE_NEWL
TRACE_ADDR
movlw h'a9'
rcall HiPhaseLoad
TRACE_DATA
rcall LoPhase
TRACE_NEWL
TRACE_ADDR
movf TABLAT,W
rcall HiPhaseLoad
TRACE_DATA
rcall LoPhase
TRACE_NEWL
TRACE_ADDR
movlw h'8d' ; Force STA abs
rcall HiPhaseLoad
TRACE_DATA
rcall LoPhase
TRACE_NEWL
TRACE_ADDR
movf ADDRL,W
rcall HiPhaseLoad
TRACE_DATA
rcall LoPhase
TRACE_NEWL
TRACE_ADDR
movf ADDRH,W
rcall HiPhaseLoad
TRACE_DATA
rcall LoPhase
TRACE_NEWL
TRACE_ADDR
rcall HiPhaseWrite
TRACE_DATA
incf ADDRL,F ; Next address
bnz LoadImage
rcall LoPhase ; Jump back to boot addr
TRACE_NEWL
TRACE_ADDR
movlw h'4c' ; .. every page
rcall HiPhaseLoad
TRACE_DATA
rcall LoPhase
TRACE_NEWL
TRACE_ADDR
movlw low BOOT_ADDR
rcall HiPhaseLoad
TRACE_DATA
rcall LoPhase
TRACE_NEWL
TRACE_ADDR
movlw high BOOT_ADDR
rcall HiPhaseLoad
TRACE_DATA
incf ADDRH,F ; Until complete
bnz LoadImage
; rcall LoPhase ; Restart using real ROM
bcf NRES_TRIS,NRES_PIN ; Assert /RES line
movlw .64
ResetPulse:
bcf PHI0_LAT,PHI0_PIN ; Make PHI0 low
nop
nop
nop
nop
nop
nop
bsf PHI0_LAT,PHI0_PIN ; Make PHI0 high
nop
nop
nop
nop
decfsz WREG,F ; Reduce pulse count
bra ResetPulse
bsf NRES_TRIS,NRES_PIN ; Release /RES line
nop
nop
nop
nop
if 0
TRACE_NEWL
TRACE_ADDR
movlw h'6c' ; .. image
rcall HiPhaseLoad
TRACE_DATA
rcall LoPhase
TRACE_NEWL
TRACE_ADDR
movlw h'fc'
rcall HiPhaseLoad
TRACE_DATA
rcall LoPhase
TRACE_NEWL
TRACE_ADDR
movlw h'ff'
rcall HiPhaseLoad
TRACE_DATA
btfss EXTRA_CYCLE,.7 ; Extra read for 65C02?
bra NoExtraRead ; No, 6502 or 65C802
rcall LoPhase ; Yes
TRACE_NEWL
TRACE_ADDR
movlw h'ff'
rcall HiPhaseLoad
TRACE_DATA
NoExtraRead:
rcall LoPhase
TRACE_NEWL
TRACE_ADDR
rcall HiPhaseRead
TRACE_DATA
rcall LoPhase
TRACE_NEWL
TRACE_ADDR
rcall HiPhaseRead
TRACE_DATA
endif
bra Execute ; And start real execution
;-------------------------------------------------------------------------------
LoPhase:
bcf PHI0_LAT,PHI0_PIN ; Make PHI0 low
setf DATA_TRIS ; Tristate data bus
bsf NRAM_LAT,NRAM_PIN ; Disable RAM
nop
nop
return
;-------------------------------------------------------------------------------
HiPhaseLoad:
bsf PHI0_LAT,PHI0_PIN
nop
btfsc RW_PORT,RW_PIN ; Make DATA port an output
clrf DATA_TRIS ; .. if CPU reading
movwf DATA_LAT ; Save data to be read
nop
nop
return
;-------------------------------------------------------------------------------
HiPhaseRead:
bsf PHI0_LAT,PHI0_PIN
nop
btfsc RW_PORT,RW_PIN ; Make RAM accessible
bcf NRAM_LAT,NRAM_PIN ; .. if CPU reading
nop
nop
return