⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 biosmain.asm

📁 6502bios,关于6502的sbc,有lcd,time,irq,模块
💻 ASM
字号:
;Chris Ward's 6502 System
;System BIOS
;16/1/2000
;To view properly, set tab size to 10

ACIA	EQU $D000		;6551 ACIA
VIA1	EQU $D100		;6522 VIA #1
VIA2	EQU $D200		;6522 VIA #2
LCD	EQU $D300		;LCD interface
RTC	EQU $D400		;DS1687 Real Time Clock
IDE	EQU $D500		;IDE interface

; VIA #1
	ORG VIA1
PORT1B	.ds 1
PORT1A	.ds 1
DDR1B	.ds 1
DDR1A	.ds 1

; VIA #2
	ORG VIA2
PORT2B	.ds 1
PORT2A	.ds 1
DDR2B	.ds 1
DDR2A	.ds 1

; connected hardware
LEDPORT	EQU PORT1B	;LEDs on VIA #1 port B
LEDDDR	EQU DDR1B
KEYPORT	EQU PORT1A	;keypad on VIA #1 port A
KEYDDR	EQU DDR1A

; *** Zero page variables
; ! These are set in stone and the addresses mustn't change because user !
; ! programs depend on them.  Add new variables at the end.              !

; [$00-$13] reserved for cc65 runtime library
;           (but could be used by machine code programs)

	ORG $14
;general-purpose temp variables for BIOS functions
ZTMP0	.ds 1
ZTMP1	.ds 1
ZTMP2	.ds 1
ZTMP3	.ds 1
ZTMP4	.ds 1
ZTMP5	.ds 1
ZTMP6	.ds 1
ZTMP7	.ds 1
ZTMP8	.ds 1
ZTMP9	.ds 1
ZTMP10	.ds 1
ZTMP11	.ds 1
ZTMP12	.ds 1
ZTMP13	.ds 1
ZTMP14	.ds 1
ZTMP15	.ds 1

;for keypad functions
KEYCOL	.ds 1	;[$24] used in scanning routine
KEYCOLN	.ds 1	;[$25]    "       "        "
KEYROW	.ds 1	;[$26]    "       "        "
KEYNEW	.ds 1	;[$27] flag indicates key has been pressed
KEYVAL	.ds 1	;[$28] value of last key pressed

;RS232 interface
SERRXF	.ds 1	;[$29] flag: 1 = new byte received
SERRX	.ds 1	;[$2A] value of byte received on serial port

;for LCD functions
MSGBASE	.ds 2	;[$2B-2C] address of message to print

;for IR functions
IRLAST	.ds 1	;[$2D]
IRLEN	.ds 1	;[$2E]

;for RTC/time functions
TI_TICK	.ds 1	;[$2F] clock ticks - 256 per second
TI_SEC	.ds 1	;[$30] time: seconds
TI_MIN	.ds 1	;[$31]       minutes
TI_HOUR	.ds 1	;[$32]       hours
TI_DAY	.ds 1	;[$33] date: day of week
TI_DATE	.ds 1	;[$34]       date
TI_MON	.ds 1	;[$35]       month
TI_YEAR	.ds 1	;[$36]       year
TI_CENT	.ds 1	;[$37]       century

;for IDE functions
IDEBUFP	.ds 2	;[$38-39] buffer pointer
IDEBUFP1	.ds 2	;[$3A-3B] temp copy of IDEBUFP
IDELBA0	.ds 1	;[$3C-3F] 28-bit LBA address (low byte first)
IDELBA1	.ds 1
IDELBA2	.ds 1
IDELBA3	.ds 1
IDELBAF	.ds 1	;[$40] flag: 1 = drive supports LBA
IDESIZE	.ds 4	;[$41-44] drive size in sectors
IDESPC	.ds 2	;[$45-46] sectors per cylinder, for CHS conversion
IDESPT	.ds 1	;[$47] sectors per track, for CHS conversion

;filesystem
DRIVES	.ds 8	;[$48-4F] available logical drives
		; codes: 00=no drive
		;        01=hard disk 1 partition 1
		;        ... 07=hard disk 1 partition 7
DRIVE	.ds 1	;[$50] selects drive number for file open, disk format etc.
FILENAME	.ds 2	;[$51-52] pointer to filename for file open
FILE	.ds 1	;[$53] logical file number for next filesystem call

;more stuff
KEYTIMER	.ds 1	;[$54] another variable for the keypad scanning routine
REGBANK	.ds 6	;[$55-5A] register bank for cc65

; *** Stack at $100-$1FF

; *** Buffers
	ORG $200
IRBUF	.ds 256	;buffer for recording IR codes
IDEBUF0	.ds 512	;buffers for data to/from IDE device
IDEBUF1	.ds 512

; *** More data
DRIVETAB	.ds 128	;drive table - 8 drives, 16 bytes per drive
FILETAB	.ds 128	;open files table - 4 files, 32 bytes per file

; ***** CODE *****
	ORG $E000

#include "6551acia.asm"
#include "ds1687.asm"
#include "fs.asm"
#include "ide.asm"
#include "keypad.asm"
#include "lcd.asm"
#include "math.asm"

; *** IRQ service routine
IRQSRV	PHA

	LDA ASTS		;interrupt from ACIA?
	BMI ASRV

	LDA #$0C		;read RTC register C
	STA RTCADDR
	LDA RTCDATA
	BPL IRQSRV9
	;interrupt from RTC...
	JSR KEYSCAN	;do keypad scan
	INC TI_TICK	;increment clock ticks
	BNE IRQSRV9
	JSR GETTIME	;update time once per second

IRQSRV9	PLA
	RTI

; *** ACIA interrupt service routine
ASRV	AND #$08		;byte received?
	BEQ IRQSRV9
	LDA ARXD		;get byte
	STA SERRX		;store byte
	INC SERRXF	;set flag
	JMP IRQSRV9

; *** Entry point on reset
RESET	NOP
	NOP
	NOP
	NOP
	JSR INIT		;do initialisation
	JMP MENU

; *** Initialise devices and variables
INIT	CLD
	LDA #$00		;clear key press flag
	STA KEYNEW
	STA KEYTIMER
	LDA #$0F		;set DDR for keypad (iiiioooo)
	STA KEYDDR
	STA KEYPORT	;set keypad columns high
	LDA #$FF		;set DDR for LEDs (oooooooo)
	STA LEDDDR
	LDA #$00		;turn LEDs off
	STA LEDPORT
	LDA #$00		;set DDR for VIA 2 port A (iiiiiiii)
	STA DDR2A		; (bit 0 = infra red)
	JSR AINIT		;setup ACIA
	JSR RINIT		;setup Real Time Clock
	JSR LINIT		;setup LCD display
	JSR MEMTEST	;perform memory test
	CLI		;enable interrupts
	JSR IDEINIT	;initialise IDE
	JSR IDEID		;get IDE drive ID
	JSR FSINIT	;initialise filesystem
	RTS

; *** Memory test
MEMMSG1	fcs "Memory test... "
	.byte $00
MEMMSG2	fcs "OK"
	.byte $00
MEMMSG3	fcs "fail at $"
	.byte $00
MEMTEST	LDX #$01		;X=high byte
	LDY #$FF		;Y=low byte
	STX $01
	LDA #0
	STA $00
	LDA #MEMMSG1	;print message
	STA MSGBASE
	LDA #MEMMSG1/256
	STA MSGBASE+1
	JSR LCDSTR
MEMLOOP	INY
	BNE MEMTST1
	INX
	CPX #$80		;reached $8000? no more RAM...
	BNE MEMTST
	LDA #$00		;turn all LEDs off
	STA LEDPORT
	LDA #MEMMSG2	;print 'OK'
	STA MSGBASE
	LDA #MEMMSG2/256
	STA MSGBASE+1
	JSR LCDSTR
	RTS
MEMTST	STX $01
	STX LEDPORT	;display high byte on LEDs
MEMTST1	LDA #$55
	STA ($00),Y
	CMP ($00),Y
	BNE MEMFAIL
	LDA #$AA
	STA ($00),Y
	CMP ($00),Y
	BNE MEMFAIL
	JMP MEMLOOP
MEMFAIL	STY $00		;store low byte of fail address
	LDA #MEMMSG3	;print 'fail at $'
	STA MSGBASE
	LDA #MEMMSG3/256
	STA MSGBASE+1
	JSR LCDSTR
	LDA $01		;print high byte
	JSR LCDHEX
	LDA $00		;print low byte
	JSR LCDHEX
MEMFAI1	LDA $01		;display high byte on leds
	STA LEDPORT
	JSR DLY00
	LDA $00		;display low byte on leds
	STA LEDPORT
	JSR DLY00
	JSR KEYSCAN	;check for keypress
	LDA KEYNEW
	BEQ MEMFAI1
	DEC KEYNEW
	RTS

; *** Main menu
MENU	JSR LCDCLR
	LDA #MENUTXT1
	STA MSGBASE
	LDA #MENUTXT1/256
	STA MSGBASE+1
	JSR LCDSTR
MENU01	JSR GETKEY
	CMP #1
	BNE MENU02
	JSR CLOCK
	JMP MENU
MENU02	CMP #2
	BNE MENU03
	JSR IRREC
	JMP MENU
MENU03	CMP #3
	BNE MENU04
	JMP TERMINAL
MENU04	CMP #4
	BNE MENU05
	JSR SLOAD
	JMP MENU
MENU05	CMP #5
	BNE MENU06
	JMP HDMENU
MENU06	CMP #6
	BNE MENU07
	JSR SCROLLER
	JMP MENU
MENU07	JMP MENU01

;40 chars:    "                                        "
MENUTXT1	fcs "1.Clock 2.IR rec 3.Terminal 4.SLOAD 5.HD"
	.byte $00

; *** Hard disk menu
HDMENU	JSR LCDCLR
	LDA #HDMENUT
	STA MSGBASE
	LDA #HDMENUT/256
	STA MSGBASE+1
	JSR LCDSTR
HDMENU01	JSR GETKEY
	CMP #1
	BNE HDMENU02
	JMP LBATEST
HDMENU02	CMP #2
	BNE HDMENU03
	JSR DLPARTAB
	JMP HDMENU
HDMENU03	CMP #0
	BNE HDMENU05
	JMP MENU
HDMENU05	JMP HDMENU01

;40 chars:    "                                        "
HDMENUT	fcs "1.LBA2CHS 2.DLPARTAB              0.Main"
	.byte $00

; *** Clock mode
CLOCKTXT1	fcs "1.Set 0.Exit"
	.byte $00

CLOCK	LDY TI_SEC	;store current seconds
	JSR LCDCLR
	JSR LCDTIME	;display time
	LDA #' '
	JSR LCDCHAR
	JSR LCDDATE	;display date
	LDA #' '		;print a couple of spaces
	JSR LCDCHAR
	JSR LCDCHAR
	LDA #CLOCKTXT1
	STA MSGBASE
	LDA #CLOCKTXT1/256
	STA MSGBASE+1
	JSR LCDSTR	;show menu text
CLOCK01	LDA KEYNEW	;key pressed?
	BNE CLOCK03	; yes
	TYA		; no
	CMP TI_SEC	;has time changed?
	BNE CLOCK		; yes - redisplay time
	JMP CLOCK01	; no
CLOCK03	LDA KEYVAL
	DEC KEYNEW
	CMP #1
	BNE CLOCK04
	JSR CLKSET
	JMP CLOCK
CLOCK04	CMP #0
	BNE CLOCK01
	RTS

CLKSET	JSR LCDCLR
	LDA #$0B		;Register B
	STA RTCADDR
	LDA #$C3		;SET, PIE, BCD, 24h, DSE
	STA RTCDATA

	LDA #2		;hours - digit 1
	JSR GETNUM
	JSR LCDHEX1
	ASL A
	ASL A
	ASL A
	ASL A
	STA ZTMP0
	LDA #9		;hours - digit 2
	JSR GETNUM
	JSR LCDHEX1
	ORA ZTMP0
	STA ZTMP0
	LDA #$04		;select hours register
	STA RTCADDR
	LDA ZTMP0		;update hours
	STA RTCDATA

	LDA #':'
	JSR LCDCHAR

	LDA #5		;minutes - digit 1
	JSR GETNUM
	JSR LCDHEX1
	ASL A
	ASL A
	ASL A
	ASL A
	STA ZTMP0
	LDA #9		;minutes - digit 2
	JSR GETNUM
	JSR LCDHEX1
	ORA ZTMP0
	STA ZTMP0
	LDA #$02		;select minutes register
	STA RTCADDR
	LDA ZTMP0		;update minutes
	STA RTCDATA

	LDA #':'
	JSR LCDCHAR

	LDA #5		;seconds - digit 1
	JSR GETNUM
	JSR LCDHEX1
	ASL A
	ASL A
	ASL A
	ASL A
	STA ZTMP0
	LDA #9		;seconds - digit 2
	JSR GETNUM
	JSR LCDHEX1
	ORA ZTMP0
	STA ZTMP0
	LDA #$00		;select seconds register
	STA RTCADDR
	LDA ZTMP0		;update seconds
	STA RTCDATA

	LDA #' '
	JSR LCDCHAR

	LDA #3		;date - digit 1
	JSR GETNUM
	JSR LCDHEX1
	ASL A
	ASL A
	ASL A
	ASL A
	STA ZTMP0
	LDA #9		;date - digit 2
	JSR GETNUM
	JSR LCDHEX1
	ORA ZTMP0
	STA ZTMP0
	LDA #$07		;select date register
	STA RTCADDR
	LDA ZTMP0
	STA RTCDATA

	LDA #'/'
	JSR LCDCHAR

	LDA #1		;month - digit 1
	JSR GETNUM
	JSR LCDHEX1
	ASL A
	ASL A
	ASL A
	ASL A
	STA ZTMP0
	LDA #9		;month - digit 2
	JSR GETNUM
	JSR LCDHEX1
	ORA ZTMP0
	STA ZTMP0
	LDA #$08		;select month register
	STA RTCADDR
	LDA ZTMP0
	STA RTCDATA

	LDA #'/'
	JSR LCDCHAR

	LDA #9		;century - digit 1
	JSR GETNUM
	JSR LCDHEX1
	ASL A
	ASL A
	ASL A
	ASL A
	STA ZTMP0
	LDA #9		;century - digit 2
	JSR GETNUM
	JSR LCDHEX1
	ORA ZTMP0
	STA ZTMP0
	LDA #$48		;select century register
	STA RTCADDR
	LDA ZTMP0
	STA RTCDATA

	LDA #9		;year - digit 1
	JSR GETNUM
	JSR LCDHEX1
	ASL A
	ASL A
	ASL A
	ASL A
	STA ZTMP0
	LDA #9		;year - digit 2
	JSR GETNUM
	JSR LCDHEX1
	ORA ZTMP0
	STA ZTMP0
	LDA #$09		;select year register
	STA RTCADDR
	LDA ZTMP0
	STA RTCDATA

	LDA #$0B		;Register B
	STA RTCADDR
	LDA #$43		;PIE, BCD, 24h, DSE
	STA RTCDATA
	RTS

; *** LCDTIME: Display time on LCD
; A,X,Y preserved
LCDTIME	PHA
	LDA TI_HOUR
	JSR LCDHEX	;Display hours
	LDA #':'		;Display a ':'
	JSR LCDCHAR
	LDA TI_MIN
	JSR LCDHEX	;Display minutes
	LDA #':'		;Display a ':'
	JSR LCDCHAR
	LDA TI_SEC
	JSR LCDHEX	;Display seconds
	PLA
	RTS

; *** LCDDATE: Display date on LCD
; A,X,Y preserved
LCDDATE	PHA
	LDA TI_DATE
	JSR LCDHEX
	LDA #'/'
	JSR LCDCHAR
	LDA TI_MON
	JSR LCDHEX
	LDA #'/'
	JSR LCDCHAR
	LDA TI_CENT
	JSR LCDHEX
	LDA TI_YEAR
	JSR LCDHEX
	PLA
	RTS

; *** Terminal mode
TERMINAL	JSR LCDCLR
TERMINA0	LDA KEYNEW
	BEQ TERMINA0
	LDA KEYVAL
	DEC KEYNEW
	TAY
	LDA HEXASCII,Y	;convert to ASCII
	JSR LCDCHAR	;print value on the LCD
	JSR TXBYTE	;transmit value on RS232 port
	JMP TERMINA0

; *** SLOAD: Load program via serial connection
SLOAD	JSR LCDCLR
	LDA #$00		;load address: $1000
	STA ZTMP0
	LDA #$10
	STA ZTMP1
	JSR RXBYTE	;get program size
	STA ZTMP2
	JSR RXBYTE
	STA ZTMP3
	JSR LCDHEX
	LDA ZTMP2
	JSR LCDHEX
	BNE SLOAD0
	DEC ZTMP3
SLOAD0	DEC ZTMP2
	LDY #0
SLOAD1	JSR RXBYTE
	STA (ZTMP0),Y
	LDA ZTMP2
	BNE SLOAD2
	DEC ZTMP3
	LDA ZTMP3
	CMP #$FF
	BEQ SLOAD3
	LDA #'.'
	JSR LCDCHAR
SLOAD2	DEC ZTMP2
	INC ZTMP0
	BNE SLOAD1
	INC ZTMP1
	JMP SLOAD1
SLOAD3	JSR LCDCLR
	JMP $1000

; *** Record IR sequence
IRRECMSG	fcs "IR Rec: "
	.byte $00
IRREC	JSR LCDCLR
	LDA #IRRECMSG
	STA MSGBASE
	LDA #IRRECMSG/256
	STA MSGBASE+1
	JSR LCDSTR
IRREC1	LDA PORT2A
	AND #$01
	STA IRLAST
	BNE IRREC1
	LDY #$00		;Y=pulse count
IRPULSE	LDX #$00		;X=pulse length
IRPULSE1	LDA PORT2A
	AND #$01
	CMP IRLAST
	STA IRLAST
	BNE IRPULSE2
	INX
	CPX #$FF		;maximum pulse length
	BNE IRPULSE1
	STY IRLEN
	LDA #'L'
	JSR LCDCHAR
	LDA #' '
	JSR LCDCHAR
	LDA IRLEN
	STA LEDPORT
	JSR LCDHEX
	JSR IRDUMP
	JSR WAITKEY
	RTS
IRPULSE2	TXA
	STA IRBUF,Y
	INY
	BNE IRPULSE
	LDA #'N'
	JSR LCDCHAR
	JSR WAITKEY
	RTS

; *** Dump recorded IR sequnce to serial port
IRDUMP	LDA IRLEN
	JSR TXBYTE
	LDY #$00
IRDUMP1	CPY IRLEN
	BEQ IRDUMPX
	LDA IRBUF,Y
	JSR TXBYTE
	INY
	JMP IRDUMP1
IRDUMPX	RTS

; *** Scroller
SCROLLER
	JSR LCDCLR
	LDA #0
	STA ZTMP0

SCROLL00	LDX #40
	LDY ZTMP0
SCROLL01	LDA SCROLTXT,Y
	JSR LCDCHAR
	DEX
	BEQ SCROLL02
	INY
	CPY #40
	BNE SCROLL01
	LDY #0
	JMP SCROLL01

SCROLL02	LDA KEYNEW
	BNE SCROLL04
	LDA TI_TICK
	CLC
	ADC #$40
SCROLL03	CMP TI_TICK
	BNE SCROLL03
	INC ZTMP0
	LDA ZTMP0
	CMP #40
	BNE SCROLL00
	LDA #0
	STA ZTMP0
	JMP SCROLL00

SCROLL04	DEC KEYNEW
	RTS

;40 chars:    "                                        "
SCROLTXT	fcs "        *** Merry Christmas ***         "

; *** Ugly old delay routines (these will probably disappear soon)
DLY00	LDX #$00
	LDY #$00
DLY00A	DEY
	BNE DLY00A
	DEX
	BNE DLY00A
	RTS

DLY01	LDY #$00
DLY01A	DEY
	BNE DLY01A
	RTS

; *** Lookup table for HEX to ASCII
HEXASCII	fcs "0123456789ABCDEF"

; *** Lookup table for powers of 2
POW2	.byte $01, $02, $04, $08, $10, $20, $40, $80

; *** Jump table for calling BIOS routines from user programs
; ! MAKE SURE THESE DON'T CHANGE ADDRESS - ADD NEW ENTRIES AT END !
	ORG $FF00
_LCDCLR	JMP LCDCLR
_LCDCHAR	JMP LCDCHAR
_LCDHEX	JMP LCDHEX
_LCDHEX1	JMP LCDHEX1
_LCDSTR	JMP LCDSTR
_LCDSTRN	JMP LCDSTRN
_LCDGETXY	JMP LCDGETXY
_LCDSETXY	JMP LCDSETXY
_KEYSCAN	JMP KEYSCAN
_WAITKEY	JMP WAITKEY
_GETKEY	JMP GETKEY
_GETNUM	JMP GETNUM
_GETHEX	JMP GETHEX
_TXBYTE	JMP TXBYTE
_RXBYTE	JMP RXBYTE
_IDERSEC	JMP IDERSEC
_IDEWSEC	JMP IDEWSEC

; *** Reset, NMI & IRQ vectors
	ORG $FFFA
	.word IRQSRV	;FIXME: should be NMI service routine
	.word RESET
	.word IRQSRV
	.end

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -