forked from MirrorRepos/RomWBW
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1808 lines
40 KiB
1808 lines
40 KiB
.Title "RTC"
|
|
;
|
|
; Program: rtc.asm
|
|
; Author: Andrew Lynch
|
|
; Date: 22 Feb 2007
|
|
; Enviroment: TASM MS-DOS Z80 Cross Assembler source for CP/M
|
|
;
|
|
;[2011/8/11] VK5DG modified for N8
|
|
; Changed base address to $88
|
|
; Changed trickle charger value to 2k+2 diodes for DS1210s
|
|
;
|
|
;[2012/2/7] WBW modified to build for either
|
|
; traditional N8VEM/Zeta or N8 via conditionals
|
|
;
|
|
;[2013/12/29] WBW modified to build for MK4
|
|
;
|
|
;[2017/11/29] WBW modified to adjust to RTC in use dynamically
|
|
; using HBIOS platform detection
|
|
;
|
|
;[2018/11/8] v1.2 PMS Add boot option. Code optimization.
|
|
;
|
|
;[2019/06/21] v1.3 Finalized RCBus Z180 support.
|
|
;
|
|
;[2019/08/11] v1.4 Support SCZ180 platform.
|
|
;
|
|
;[2020/02/02] v1.5 PMS Basic command line support
|
|
;
|
|
;[2020/05/15] v1.6 Added Warm Start option
|
|
;
|
|
;[2021/07/10] v1.7 Support MBC (AJL)
|
|
;
|
|
;[2022/03/27] v1.8 Support RHYOPHYRE
|
|
;
|
|
;[2023/07/07] v1.9 Support DUODYNE
|
|
;
|
|
;[2024/09/02] v1.10 Support Genesis STD Z180
|
|
;
|
|
; Constants
|
|
;
|
|
mask_data .EQU %10000000 ; RTC data line
|
|
mask_clk .EQU %01000000 ; RTC Serial Clock line
|
|
mask_rd .EQU %00100000 ; Enable data read from RTC
|
|
mask_rst .EQU %00010000 ; De-activate RTC reset line
|
|
|
|
PORT_SBC .EQU $70 ; RTC port for SBC/ZETA
|
|
PORT_N8 .EQU $88 ; RTC port for N8
|
|
PORT_MK4 .EQU $8A ; RTC port for MK4
|
|
PORT_RCZ80 .EQU $C0 ; RTC port for RCBus
|
|
PORT_RCZ180 .EQU $0C ; RTC port for RCBus
|
|
PORT_EZZ80 .EQU $C0 ; RTC port for EZZ80 (actually does not have one!!!)
|
|
PORT_SCZ180 .EQU $0C ; RTC port for SCZ180
|
|
PORT_DYNO .EQU $0C ; RTC port for DYNO
|
|
PORT_RCZ280 .EQU $C0 ; RTC port for RCZ280
|
|
PORT_MBC .EQU $70 ; RTC port for MBC
|
|
PORT_RPH .EQU $84 ; RTC port for RHYOPHYRE
|
|
PORT_DUO .EQU $94 ; RTC port for DUODYNE
|
|
PORT_STDZ180 .EQU $84 ; RTC Port for STD Bus Z180 board
|
|
|
|
|
|
BDOS .EQU 5 ; BDOS invocation vector
|
|
FCB .EQU 05CH ; Start of command line
|
|
|
|
;BID_BOOT .EQU $00
|
|
;HB_BNKCALL .EQU $FFF9
|
|
|
|
BF_SYSRESET .EQU $F0 ; RESTART SYSTEM
|
|
|
|
BF_SYSRES_INT .EQU $00 ; RESET HBIOS INTERNAL
|
|
BF_SYSRES_WARM .EQU $01 ; WARM START (RESTART BOOT LOADER)
|
|
BF_SYSRES_COLD .EQU $02 ; COLD START
|
|
|
|
;
|
|
; Program
|
|
;
|
|
.ORG 0100H
|
|
|
|
LOOP:
|
|
LD DE,MSG
|
|
LD C,09H ; CP/M write string to console call
|
|
CALL 0005H
|
|
|
|
; program starts here
|
|
|
|
CALL RTC_INIT ; Program initialization
|
|
|
|
CALL RTC_TOP_LOOP
|
|
|
|
LD C,00H ; CP/M system reset call - shut down
|
|
CALL 0005H
|
|
|
|
HALT ; This code is never reached
|
|
|
|
|
|
; function HEXSTR
|
|
; input number in A
|
|
; output upper nibble of number in ASCII in H
|
|
; output lower nibble of number in ASCII in L
|
|
; uses BC
|
|
;
|
|
; based on following algorithm:
|
|
;
|
|
; const
|
|
; hextab : string = ('0','1','2','3','4','5','6','7','8',
|
|
; '9','A','B','C','D','E','F');
|
|
;
|
|
; PROCEDURE hexstr(n: int): ^string;
|
|
; BEGIN
|
|
; n := n and 255;
|
|
; tmpstr[1] := hextab[n / 16];
|
|
; tmpstr[2] := hextab[n and 15];
|
|
; tmpstr[0] := #2;
|
|
; return @tmpstr;
|
|
; END;
|
|
|
|
|
|
HEXSTR:
|
|
PUSH BC ;SAVE BC
|
|
LD B,A
|
|
RLC A ;DO HIGH NIBBLE FIRST
|
|
RLC A
|
|
RLC A
|
|
RLC A
|
|
AND 0FH ;ONLY THIS NOW
|
|
ADD A,30H ;TRY A NUMBER
|
|
CP 3AH ;TEST IT
|
|
JR C,HEXSTR1 ;IF CY SET SAVE 'NUMBER' in H
|
|
ADD A,07H ;MAKE IT AN ALPHA
|
|
HEXSTR1:
|
|
LD H,A ;SAVE 'ALPHA' in H
|
|
LD A,B ;NEXT NIBBLE
|
|
AND 0FH ;JUST THIS
|
|
ADD A,30H ;TRY A NUMBER
|
|
CP 3AH ;TEST IT
|
|
JR C,HEXSTR2 ;IF CY SET SAVE 'NUMBER' in L
|
|
ADD A,07H ;MAKE IT ALPHA
|
|
|
|
HEXSTR2:
|
|
LD L,A ;SAVE 'ALPHA' in L
|
|
POP BC ;RESTORE BC
|
|
RET
|
|
|
|
|
|
;*****************************************************
|
|
;* GET K.B. DATA & MAKE IT 'HEX'
|
|
;*****************************************************
|
|
|
|
HEXIN:
|
|
PUSH BC ;SAVE BC REGS.
|
|
CALL NIBL ;DO A NIBBLE
|
|
RLC A ;MOVE FIRST BYTE UPPER NIBBLE
|
|
RLC A
|
|
RLC A
|
|
RLC A
|
|
LD B,A ;SAVE ROTATED BYTE
|
|
PUSH BC
|
|
|
|
CALL NIBL ;DO NEXT NIBBLE
|
|
POP BC
|
|
ADD A,B ;COMBINE NIBBLES IN ACC.
|
|
POP BC ;RESTORE BC
|
|
RET ;DONE
|
|
NIBL:
|
|
LD C,01H ; CP/M console input call
|
|
CALL 0005H ;GET K.B. DATA
|
|
CP 40H ;TEST FOR ALPHA
|
|
JR NC,ALPH
|
|
AND 0FH ;GET THE BITS
|
|
RET
|
|
ALPH:
|
|
AND 0FH ;GET THE BITS
|
|
ADD A,09H ;MAKE IT HEX A-F
|
|
RET
|
|
|
|
; function RTC_IN
|
|
;
|
|
; read a byte from RTC port, return in A
|
|
; NOTE: port address is dynamically set in RTC_INIT
|
|
|
|
RTC_IN:
|
|
INP .EQU $ + 1
|
|
IN A,($FF)
|
|
RET
|
|
|
|
; function RTC_OUT
|
|
;
|
|
; write a byte to RTC port, value in A
|
|
; NOTE: port address is dynamically set in RTC_INIT
|
|
|
|
RTC_OUT:
|
|
OUTP .EQU $ + 1
|
|
OUT ($FF),A
|
|
RET
|
|
|
|
; function RTC_BIT_DELAY
|
|
;
|
|
; based on following algorithm:
|
|
;
|
|
; { Make a short delay }
|
|
; PROCEDURE rtc_bit_delay;
|
|
; var
|
|
; x : int;
|
|
; BEGIN
|
|
; x := 3;
|
|
; END;
|
|
|
|
RTC_BIT_DELAY: ; purpose is to delay ~36 uS or 144 t-states at 4MHz
|
|
PUSH AF ; 11 t-states
|
|
LD A,07H ; 7 t-states ADJUST THE TIME 13h IS FOR 4 MHZ
|
|
RTC_BIT_DELAY1:
|
|
DEC A ; 4 t-states DEC COUNTER. 4 T-states = 1 uS.
|
|
JP NZ,RTC_BIT_DELAY1 ; 10 t-states JUMP TO PAUSELOOP2 IF A <> 0.
|
|
|
|
NOP ; 4 t-states
|
|
NOP ; 4 t-states
|
|
POP AF ; 10 t-states
|
|
RET ; 10 t-states (144 t-states total)
|
|
|
|
|
|
; function RTC_RESET
|
|
;
|
|
; based on following algorithm:
|
|
;
|
|
; { Output a RTC reset signal }
|
|
; PROCEDURE rtc_reset;
|
|
; BEGIN
|
|
; out(rtc_base,mask_data + mask_rd);
|
|
; rtc_bit_delay();
|
|
; rtc_bit_delay();
|
|
; out(rtc_base,mask_data + mask_rd + mask_rst);
|
|
; rtc_bit_delay();
|
|
; rtc_bit_delay();
|
|
; END;
|
|
;
|
|
RTC_RESET:
|
|
LD A,mask_data + mask_rd
|
|
;OUT (RTC),A
|
|
CALL RTC_OUT
|
|
CALL RTC_BIT_DELAY
|
|
CALL RTC_BIT_DELAY
|
|
LD A,mask_data + mask_rd + mask_rst
|
|
;OUT (RTC),A
|
|
CALL RTC_OUT
|
|
CALL RTC_BIT_DELAY
|
|
CALL RTC_BIT_DELAY
|
|
RET
|
|
|
|
|
|
; function RTC_RESET_ON
|
|
;
|
|
; based on following algorithm:
|
|
;
|
|
; { Assert RTC reset signal }
|
|
; PROCEDURE rtc_reset_on;
|
|
; BEGIN
|
|
; out(rtc_base,mask_data + mask_rd);
|
|
; rtc_bit_delay();
|
|
; rtc_bit_delay();
|
|
; END;
|
|
|
|
RTC_RESET_ON:
|
|
LD A,mask_data + mask_rd
|
|
;OUT (RTC),A
|
|
CALL RTC_OUT
|
|
CALL RTC_BIT_DELAY
|
|
CALL RTC_BIT_DELAY
|
|
RET
|
|
|
|
; function RTC_RESET_OFF
|
|
;
|
|
; based on following algorithm:
|
|
;
|
|
; { De-assert RTC reset signal }
|
|
; PROCEDURE rtc_reset_off;
|
|
; BEGIN
|
|
; out(rtc_base,mask_data + mask_rd + mask_rst);
|
|
; rtc_bit_delay();
|
|
; rtc_bit_delay();
|
|
; END;
|
|
|
|
RTC_RESET_OFF:
|
|
LD A,mask_data + mask_rd + mask_rst
|
|
;OUT (RTC),A
|
|
CALL RTC_OUT
|
|
CALL RTC_BIT_DELAY
|
|
CALL RTC_BIT_DELAY
|
|
RET
|
|
|
|
; function RTC_WR
|
|
; input value in C
|
|
; uses A
|
|
;
|
|
; PROCEDURE rtc_wr(n : int);
|
|
; var
|
|
; i : int;
|
|
; BEGIN
|
|
; for i := 0 while i < 8 do inc(i) loop
|
|
; if (n and 1) <> 0 then
|
|
; out(rtc_base,mask_rst + mask_data);
|
|
; rtc_bit_delay();
|
|
; out(rtc_base,mask_rst + mask_clk + mask_data);
|
|
; else
|
|
; out(rtc_base,mask_rst);
|
|
; rtc_bit_delay();
|
|
; out(rtc_base,mask_rst + mask_clk);
|
|
; end;
|
|
; rtc_bit_delay();
|
|
; n := shr(n,1);
|
|
; end loop;
|
|
; END;
|
|
|
|
RTC_WR:
|
|
XOR A ; set A=0 index counter of FOR loop
|
|
|
|
RTC_WR1:
|
|
PUSH AF ; save accumulator as it is the index counter in FOR loop
|
|
LD A,C ; get the value to be written in A from C (passed value to write in C)
|
|
BIT 0,A ; is LSB a 0 or 1?
|
|
JP Z,RTC_WR2 ; if it's a 0, handle it at RTC_WR2.
|
|
; LSB is a 1, handle it below
|
|
; setup RTC latch with RST and DATA high, SCLK low
|
|
LD A,mask_rst + mask_data
|
|
;OUT (RTC),A ; output to RTC latch
|
|
CALL RTC_OUT
|
|
CALL RTC_BIT_DELAY ; let it settle a while
|
|
; setup RTC with RST, DATA, and SCLK high
|
|
LD A,mask_rst + mask_clk + mask_data
|
|
;OUT (RTC),A ; output to RTC latch
|
|
CALL RTC_OUT
|
|
JP RTC_WR3 ; exit FOR loop
|
|
|
|
RTC_WR2:
|
|
; LSB is a 0, handle it below
|
|
LD A,mask_rst ; setup RTC latch with RST high, SCLK and DATA low
|
|
;OUT (RTC),A ; output to RTC latch
|
|
CALL RTC_OUT
|
|
CALL RTC_BIT_DELAY ; let it settle a while
|
|
; setup RTC with RST and SCLK high, DATA low
|
|
LD A,mask_rst + mask_clk
|
|
;OUT (RTC),A ; output to RTC latch
|
|
CALL RTC_OUT
|
|
|
|
RTC_WR3:
|
|
CALL RTC_BIT_DELAY ; let it settle a while
|
|
RRC C ; move next bit into LSB position for processing to RTC
|
|
POP AF ; recover accumulator as it is the index counter in FOR loop
|
|
INC A ; increment A in FOR loop (A=A+1)
|
|
CP $08 ; is A < $08 ?
|
|
JP NZ,RTC_WR1 ; No, do FOR loop again
|
|
RET ; Yes, end function and return
|
|
|
|
|
|
; function RTC_RD
|
|
; output value in C
|
|
; uses A
|
|
;
|
|
; function RTC_RD
|
|
;
|
|
; PROCEDURE rtc_rd(): int ;
|
|
; var
|
|
; i,n,mask : int;
|
|
; BEGIN
|
|
; n := 0;
|
|
; mask := 1;
|
|
; for i := 0 while i < 8 do inc(i) loop
|
|
; out(rtc_base,mask_rst + mask_rd);
|
|
; rtc_bit_delay();
|
|
; if (in(rtc_base) and #1) <> #0 then
|
|
; { Data = 1 }
|
|
; n := n + mask;
|
|
; else
|
|
; { Data = 0 }
|
|
; end;
|
|
; mask := shl(mask,1);
|
|
; out(rtc_base,mask_rst + mask_clk + mask_rd);
|
|
; rtc_bit_delay();
|
|
; end loop;
|
|
; return n;
|
|
; END;
|
|
|
|
RTC_RD:
|
|
XOR A ; set A=0 index counter of FOR loop
|
|
LD C,$00 ; set C=0 output of RTC_RD is passed in C
|
|
LD B,$01 ; B is mask value
|
|
|
|
RTC_RD1:
|
|
PUSH AF ; save accumulator as it is the index counter in FOR loop
|
|
; setup RTC with RST and RD high, SCLK low
|
|
LD A,mask_rst + mask_rd
|
|
;OUT (RTC),A ; output to RTC latch
|
|
CALL RTC_OUT
|
|
CALL RTC_BIT_DELAY ; let it settle a while
|
|
;IN A,(RTC) ; input from RTC latch
|
|
CALL RTC_IN ; input from RTC latch
|
|
BIT 0,A ; is LSB a 0 or 1?
|
|
JP Z,RTC_RD2 ; if LSB is a 1, handle it below
|
|
LD A,C
|
|
ADD A,B
|
|
LD C,A
|
|
; INC C
|
|
; if LSB is a 0, skip it (C=C+0)
|
|
RTC_RD2:
|
|
RLC B ; move input bit out of LSB position to save it in C
|
|
; setup RTC with RST, SCLK high, and RD high
|
|
LD A,mask_rst + mask_clk + mask_rd
|
|
;OUT (RTC),A ; output to RTC latch
|
|
CALL RTC_OUT
|
|
CALL RTC_BIT_DELAY ; let it settle
|
|
POP AF ; recover accumulator as it is the index counter in FOR loop
|
|
INC A ; increment A in FOR loop (A=A+1)
|
|
CP $08 ; is A < $08 ?
|
|
JP NZ,RTC_RD1 ; No, do FOR loop again
|
|
RET ; Yes, end function and return. Read RTC value is in C
|
|
|
|
; function RTC_WRITE
|
|
; input address in D
|
|
; input value in E
|
|
; uses A
|
|
;
|
|
; based on following algorithm:
|
|
;
|
|
; PROCEDURE rtc_write(address, value: int);
|
|
; BEGIN
|
|
; lock();
|
|
; rtc_reset_off();
|
|
; { Write command }
|
|
; rtc_wr(128 + shl(address and $3f,1));
|
|
; { Write data }
|
|
; rtc_wr(value and $ff);
|
|
; rtc_reset_on();
|
|
; unlock();
|
|
; END;
|
|
|
|
RTC_WRITE:
|
|
DI ; disable interrupts during critical section
|
|
CALL RTC_RESET_OFF ; turn off RTC reset
|
|
LD A,D ; bring into A the address from D
|
|
; AND $3F ; keep only bits 6 LSBs, discard 2 MSBs
|
|
AND %00111111 ; keep only bits 6 LSBs, discard 2 MSBs
|
|
RLC A ; rotate address bits to the left
|
|
; ADD A,$80 ; set MSB to one for DS1302 COMMAND BYTE (WRITE)
|
|
ADD A,%10000000 ; set MSB to one for DS1302 COMMAND BYTE (WRITE)
|
|
LD C,A ; RTC_WR expects write data (address) in reg C
|
|
CALL RTC_WR ; write address to DS1302
|
|
LD A,E ; start processing value
|
|
AND $FF ; seems unnecessary, probably delete since all values are 8-bit
|
|
LD C,A ; RTC_WR expects write data (value) in reg C
|
|
CALL RTC_WR ; write address to DS1302
|
|
CALL RTC_RESET_ON ; turn on RTC reset
|
|
EI
|
|
RET
|
|
|
|
|
|
; function RTC_READ
|
|
; input address in D
|
|
; output value in C
|
|
; uses A
|
|
;
|
|
; based on following algorithm
|
|
;
|
|
; PROCEDURE rtc_read(address: int): int;
|
|
; var
|
|
; n : int;
|
|
; BEGIN
|
|
; lock();
|
|
; rtc_reset_off();
|
|
; { Write command }
|
|
; rtc_wr(128 + shl(address and $3f,1) + 1);
|
|
; { Read data }
|
|
; n := rtc_rd();
|
|
; rtc_reset_on();
|
|
; unlock();
|
|
; return n;
|
|
; END;
|
|
|
|
RTC_READ:
|
|
DI ; disable interrupts during critical section
|
|
CALL RTC_RESET_OFF ; turn off RTC reset
|
|
LD A,D ; bring into A the address from D
|
|
AND $3F ; keep only bits 6 LSBs, discard 2 MSBs
|
|
RLC A ; rotate address bits to the left
|
|
ADD A,$81 ; set MSB to one for DS1302 COMMAND BYTE (READ)
|
|
LD C,A ; RTC_WR expects write data (address) in reg C
|
|
CALL RTC_WR ; write address to DS1302
|
|
CALL RTC_RD ; read value from DS1302 (value is in reg C)
|
|
CALL RTC_RESET_ON ; turn on RTC reset
|
|
EI
|
|
RET
|
|
|
|
|
|
; function RTC_WR_PROTECT
|
|
; input D (address) $07
|
|
; input E (value) $80
|
|
; uses A
|
|
;
|
|
; based on following algorithm
|
|
;
|
|
; PROCEDURE rtc_wr_protect;
|
|
; BEGIN
|
|
; rtc_write(7,128);
|
|
; END;
|
|
|
|
RTC_WR_PROTECT:
|
|
; LD D,$07
|
|
LD D,%00000111
|
|
; LD E,$80
|
|
LD E,%10000000
|
|
CALL RTC_WRITE
|
|
RET
|
|
|
|
|
|
; function RTC_WR_UNPROTECT
|
|
; input D (address) $07
|
|
; input E (value) $00
|
|
; uses A
|
|
;
|
|
; based on following algorithm
|
|
;
|
|
; PROCEDURE rtc_wr_unprotect;
|
|
; BEGIN
|
|
; rtc_write(7,0);
|
|
; END;
|
|
|
|
RTC_WR_UNPROTECT:
|
|
; LD D,$07
|
|
LD D,%00000111
|
|
; LD E,$00
|
|
LD E,%00000000
|
|
CALL RTC_WRITE
|
|
RET
|
|
|
|
|
|
; function RTC_GET_TIME
|
|
; input HL (memory address of buffer)
|
|
; uses A,C,D,E
|
|
;
|
|
; based on following algorithm
|
|
;
|
|
; PROCEDURE rtc_get_time(var buf: string);
|
|
; var
|
|
; n : int;
|
|
; BEGIN
|
|
; lock();
|
|
; rtc_reset_off();
|
|
; { Write command, burst read }
|
|
; rtc_wr(255 - 64);
|
|
; { Read seconds }
|
|
; n := rtc_rd(); 0
|
|
; buf[16] := char(((n / 16) and $07)) + '0';
|
|
; buf[17] := char((n and $0f)) + '0';
|
|
; { Read minutes }
|
|
; n := rtc_rd(); 1
|
|
; buf[13] := char(((n / 16) and $07)) + '0';
|
|
; buf[14] := char((n and $0f)) + '0';
|
|
; buf[15] := ':';
|
|
; { Read hours }
|
|
; n := rtc_rd(); 2
|
|
; buf[10] := char(((n / 16) and $03)) + '0';
|
|
; buf[11] := char((n and $0f)) + '0';
|
|
; buf[12] := ':';
|
|
; { Read date }
|
|
; n := rtc_rd(); 3
|
|
; buf[7] := char(((n / 16) and $03)) + '0';
|
|
; buf[8] := char((n and $0f)) + '0';
|
|
; buf[9] := ' ';
|
|
; { Read month }
|
|
; n := rtc_rd(); 4
|
|
; buf[4] := char(((n / 16) and $03)) + '0';
|
|
; buf[5] := char((n and $0f)) + '0';
|
|
; buf[6] := '-';
|
|
; { Read day }
|
|
; n := rtc_rd(); 5
|
|
; {
|
|
; buf[4] := char(((n / 16) and $03)) + '0';
|
|
; buf[4] := char((n and $0f)) + '0';
|
|
; }
|
|
; { Read year }
|
|
; n := rtc_rd(); 6
|
|
; buf[1] := char(((n / 16) and $0f)) + '0';
|
|
; buf[2] := char((n and $0f)) + '0';
|
|
; buf[3] := '-';
|
|
; length(buf) := 17;
|
|
; rtc_reset_on();
|
|
; unlock();
|
|
; END rtc_get_time;
|
|
|
|
RTC_GET_TIME:
|
|
DI ; disable interrupts during DS1302 read
|
|
CALL RTC_RESET_OFF ; turn of RTC reset
|
|
; { Write command, burst read }
|
|
LD C,%10111111 ; (255 - 64)
|
|
CALL RTC_WR ; send COMMAND BYTE (BURST READ) to DS1302
|
|
|
|
; { Read seconds }
|
|
|
|
CALL RTC_RD ; read value from DS1302, value is in Reg C
|
|
|
|
; digit 16
|
|
LD A,C ; put value output in Reg C into accumulator
|
|
RLC A
|
|
RLC A
|
|
RLC A
|
|
RLC A
|
|
AND $07
|
|
ADD A,'0'
|
|
LD (RTC_PRINT_BUFFER+15),A
|
|
|
|
; digit 17
|
|
LD A,C ; put value output in Reg C into accumulator
|
|
AND $0F
|
|
ADD A,'0'
|
|
LD (RTC_PRINT_BUFFER+16),A
|
|
|
|
; { Read minutes }
|
|
|
|
CALL RTC_RD ; read value from DS1302, value is in Reg C
|
|
|
|
; digit 13
|
|
LD A,C ; put value output in Reg C into accumulator
|
|
RLC A
|
|
RLC A
|
|
RLC A
|
|
RLC A
|
|
AND $07
|
|
ADD A,'0'
|
|
LD (RTC_PRINT_BUFFER+12),A
|
|
|
|
; digit 14
|
|
LD A,C ; put value output in Reg C into accumulator
|
|
AND $0F
|
|
ADD A,'0'
|
|
LD (RTC_PRINT_BUFFER+13),A
|
|
|
|
; digit 15
|
|
LD A,':'
|
|
LD (RTC_PRINT_BUFFER+14),A
|
|
|
|
; { Read hours }
|
|
|
|
CALL RTC_RD ; read value from DS1302, value is in Reg C
|
|
|
|
; digit 10
|
|
LD A,C ; put value output in Reg C into accumulator
|
|
RLC A
|
|
RLC A
|
|
RLC A
|
|
RLC A
|
|
AND $03
|
|
ADD A,'0'
|
|
LD (RTC_PRINT_BUFFER+09),A
|
|
|
|
; digit 11
|
|
LD A,C ; put value output in Reg C into accumulator
|
|
AND $0F
|
|
ADD A,'0'
|
|
LD (RTC_PRINT_BUFFER+10),A
|
|
|
|
; digit 12
|
|
LD A,':'
|
|
LD (RTC_PRINT_BUFFER+11),A
|
|
|
|
; { Read date }
|
|
|
|
CALL RTC_RD ; read value from DS1302, value is in Reg C
|
|
|
|
; digit 07
|
|
LD A,C ; put value output in Reg C into accumulator
|
|
RLC A
|
|
RLC A
|
|
RLC A
|
|
RLC A
|
|
AND $03
|
|
ADD A,'0'
|
|
LD (RTC_PRINT_BUFFER+06),A
|
|
|
|
; digit 08
|
|
LD A,C ; put value output in Reg C into accumulator
|
|
AND $0F
|
|
ADD A,'0'
|
|
LD (RTC_PRINT_BUFFER+07),A
|
|
|
|
; digit 09
|
|
LD A,' '
|
|
LD (RTC_PRINT_BUFFER+08),A
|
|
|
|
; { Read month }
|
|
|
|
CALL RTC_RD ; read value from DS1302, value is in Reg C
|
|
|
|
; digit 04
|
|
LD A,C ; put value output in Reg C into accumulator
|
|
RLC A
|
|
RLC A
|
|
RLC A
|
|
RLC A
|
|
AND $03
|
|
ADD A,'0'
|
|
LD (RTC_PRINT_BUFFER+03),A
|
|
|
|
; digit 05
|
|
LD A,C ; put value output in Reg C into accumulator
|
|
AND $0F
|
|
ADD A,'0'
|
|
LD (RTC_PRINT_BUFFER+04),A
|
|
|
|
; digit 06
|
|
LD A,'-'
|
|
LD (RTC_PRINT_BUFFER+05),A
|
|
|
|
; { Read day }
|
|
|
|
CALL RTC_RD ; read value from DS1302, value is in Reg C
|
|
|
|
; digit 04
|
|
; LD A,C ; put value output in Reg C into accumulator
|
|
; RLC A
|
|
; RLC A
|
|
; RLC A
|
|
; RLC A
|
|
; AND $03
|
|
; ADD A,'0'
|
|
; LD (RTC_PRINT_BUFFER+03),A
|
|
|
|
; digit 04
|
|
; LD A,C ; put value output in Reg C into accumulator
|
|
; AND $0F
|
|
; ADD A,'0'
|
|
; LD (RTC_PRINT_BUFFER+03),A
|
|
|
|
; add special code to put "DAY" value at end of string until better solution known
|
|
|
|
; digit 18
|
|
LD A,'-'
|
|
LD (RTC_PRINT_BUFFER+17),A
|
|
|
|
; digit 19
|
|
LD A,C ; put value output in Reg C into accumulator
|
|
RLC A
|
|
RLC A
|
|
RLC A
|
|
RLC A
|
|
AND $0F
|
|
ADD A,'0'
|
|
LD (RTC_PRINT_BUFFER+18),A
|
|
|
|
; digit 20
|
|
LD A,C ; put value output in Reg C into accumulator
|
|
AND $0F
|
|
ADD A,'0'
|
|
LD (RTC_PRINT_BUFFER+19),A
|
|
|
|
; { Read year }
|
|
|
|
CALL RTC_RD ; read value from DS1302, value is in Reg C
|
|
|
|
; digit 01
|
|
LD A,C ; put value output in Reg C into accumulator
|
|
RLC A
|
|
RLC A
|
|
RLC A
|
|
RLC A
|
|
AND $0F
|
|
ADD A,'0'
|
|
LD (RTC_PRINT_BUFFER+00),A
|
|
|
|
; digit 02
|
|
LD A,C ; put value output in Reg C into accumulator
|
|
AND $0F
|
|
ADD A,'0'
|
|
LD (RTC_PRINT_BUFFER+01),A
|
|
|
|
; digit 03
|
|
LD A,'-'
|
|
LD (RTC_PRINT_BUFFER+02),A
|
|
|
|
CALL RTC_RESET_ON ; turn RTC reset back on
|
|
EI ; re-enable interrupts
|
|
|
|
RET ; Yes, end function and return
|
|
|
|
|
|
; function RTC_SET_NOW
|
|
; uses A, D, E
|
|
;
|
|
; based on following algorithm
|
|
;
|
|
; { Set time to 96-02-18 19:43:00 }
|
|
; PROCEDURE rtc_set_now;
|
|
; BEGIN
|
|
; rtc_wr_unprotect();
|
|
; { Set seconds }
|
|
; rtc_write(0,0);
|
|
; { Set minutes }
|
|
; rtc_write(1,$43);
|
|
; { Set hours }
|
|
; rtc_write(2,$19);
|
|
; { Set date }
|
|
; rtc_write(3,$18);
|
|
; { Set month }
|
|
; rtc_write(4,$02);
|
|
; { Set day }
|
|
; rtc_write(5,$07);
|
|
; { Set year }
|
|
; rtc_write(6,$96);
|
|
; rtc_wr_protect();
|
|
; END;
|
|
|
|
RTC_SET_NOW:
|
|
; set time to 07-02-23 19:45:00-05 <-Friday
|
|
CALL RTC_WR_UNPROTECT
|
|
; seconds
|
|
LD D,$00
|
|
LD A,(SECONDS)
|
|
LD E,A
|
|
CALL RTC_WRITE
|
|
|
|
; minutes
|
|
LD D,$01
|
|
LD A,(MINUTES)
|
|
LD E,A
|
|
CALL RTC_WRITE
|
|
|
|
; hours
|
|
LD D,$02
|
|
LD A,(HOURS)
|
|
LD E,A
|
|
CALL RTC_WRITE
|
|
|
|
; date
|
|
LD D,$03
|
|
LD A,(DATE)
|
|
LD E,A
|
|
CALL RTC_WRITE
|
|
|
|
; month
|
|
LD D,$04
|
|
LD A,(MONTH)
|
|
LD E,A
|
|
CALL RTC_WRITE
|
|
|
|
; day
|
|
LD D,$05
|
|
LD A,(DAY)
|
|
LD E,A
|
|
CALL RTC_WRITE
|
|
|
|
; year
|
|
LD D,$06
|
|
LD A,(YEAR)
|
|
LD E,A
|
|
CALL RTC_WRITE
|
|
|
|
CALL RTC_WR_PROTECT
|
|
RET
|
|
|
|
RTC_INIT_NOW:
|
|
; set time to Current Time
|
|
|
|
; year
|
|
LD DE,RTC_TOP_LOOP1_INIT_YEAR
|
|
LD C,09H ; CP/M write string to console call
|
|
CALL 0005H
|
|
CALL HEXIN
|
|
LD (YEAR),A
|
|
|
|
; month
|
|
LD DE,RTC_TOP_LOOP1_INIT_MONTH
|
|
LD C,09H ; CP/M write string to console call
|
|
CALL 0005H
|
|
CALL HEXIN
|
|
LD (MONTH),A
|
|
|
|
; date
|
|
LD DE,RTC_TOP_LOOP1_INIT_DATE
|
|
LD C,09H ; CP/M write string to console call
|
|
CALL 0005H
|
|
CALL HEXIN
|
|
LD (DATE),A
|
|
|
|
; hours
|
|
LD DE,RTC_TOP_LOOP1_INIT_HOURS
|
|
LD C,09H ; CP/M write string to console call
|
|
CALL 0005H
|
|
CALL HEXIN
|
|
LD (HOURS),A
|
|
|
|
; minutes
|
|
LD DE,RTC_TOP_LOOP1_INIT_MINUTES
|
|
LD C,09H ; CP/M write string to console call
|
|
CALL 0005H
|
|
CALL HEXIN
|
|
LD (MINUTES),A
|
|
|
|
; seconds
|
|
LD DE,RTC_TOP_LOOP1_INIT_SECONDS
|
|
LD C,09H ; CP/M write string to console call
|
|
CALL 0005H
|
|
CALL HEXIN
|
|
LD (SECONDS),A
|
|
|
|
; day
|
|
LD DE,RTC_TOP_LOOP1_INIT_DAY
|
|
LD C,09H ; CP/M write string to console call
|
|
CALL 0005H
|
|
CALL HEXIN
|
|
LD (DAY),A
|
|
|
|
RET
|
|
|
|
|
|
; function RTC_RESTART
|
|
;
|
|
; uses A, D, E,
|
|
;
|
|
; based on the following algorithm
|
|
;
|
|
; { Restart clock, set seconds to 00 }
|
|
; PROCEDURE rtc_restart;
|
|
; BEGIN
|
|
; rtc_wr_unprotect();
|
|
; { Set seconds }
|
|
; rtc_write(0,0);
|
|
; rtc_wr_protect();
|
|
; END;
|
|
|
|
RTC_RESTART:
|
|
CALL RTC_WR_UNPROTECT
|
|
LD D,$00
|
|
LD E,$00
|
|
CALL RTC_WRITE
|
|
CALL RTC_WR_PROTECT
|
|
RET
|
|
|
|
|
|
; function RTC_CHARGE_ENABLE
|
|
;
|
|
; uses A, D, E
|
|
;
|
|
; based on following algorithm
|
|
;
|
|
; PROCEDURE rtc_charge_enable;
|
|
; BEGIN
|
|
; rtc_wr_unprotect();
|
|
; { Enable trickle charger, 2kohm, 1 diode }
|
|
; rtc_write(8,$A5);
|
|
; rtc_wr_protect();
|
|
; END;
|
|
;
|
|
; Trickle Charge Current:
|
|
;
|
|
; Imax = (5.0V - (0.7 * Ndiode)) / R
|
|
; (5.0 - (0.7 * 1)) / 2000 = .00215A = 2.15 milliamps
|
|
; (5.0 - (0.7 * 1)) / 8000 = 0.0005375A = .537 milliamps
|
|
;
|
|
|
|
RTC_CHARGE_ENABLE
|
|
CALL RTC_WR_UNPROTECT
|
|
LD D,$08
|
|
LD E,$A5
|
|
CALL RTC_WRITE
|
|
CALL RTC_WR_PROTECT
|
|
RET
|
|
|
|
|
|
; function RTC_CHARGE_DISABLE
|
|
;
|
|
; uses A, D, E
|
|
;
|
|
; based on following algorithm
|
|
;
|
|
; PROCEDURE rtc_charge_disable;
|
|
; BEGIN
|
|
; rtc_wr_unprotect();
|
|
; { Disable trickle charger}
|
|
; rtc_write(8,$00);
|
|
; rtc_wr_protect();
|
|
; END;
|
|
|
|
RTC_CHARGE_DISABLE
|
|
CALL RTC_WR_UNPROTECT
|
|
LD D,$08
|
|
LD E,$00
|
|
CALL RTC_WRITE
|
|
CALL RTC_WR_PROTECT
|
|
RET
|
|
|
|
|
|
; function TEST_BIT_DELAY
|
|
;
|
|
; based on the following algorithm
|
|
;
|
|
;
|
|
; PROCEDURE test_bit_delay();
|
|
; var
|
|
; i,t0,t1 : int;
|
|
; BEGIN
|
|
; putln("Testing bit delay...");
|
|
; t0 := sys_time();
|
|
; for i := 0 while i < 1000 do inc(i) loop
|
|
; rtc_bit_delay();
|
|
; end loop;
|
|
; t1 := sys_time();
|
|
; putln(i," rtc_bit_delay calls took ",t1-t0," ms.");
|
|
; END;
|
|
|
|
RTC_TEST_BIT_DELAY
|
|
LD DE,TESTING_BIT_DELAY_MSG
|
|
LD C,09H ; CP/M write string to console call
|
|
CALL 0005H
|
|
LD C,01H ; CP/M console input call
|
|
CALL 0005H
|
|
|
|
; test should take approximately 43 seconds based on the following code analysis
|
|
; of Z80 T-states on a 4 MHz processor
|
|
; =(4+15*(7+255*(7+255*(17+144+4+10)+4+10)+10)+7)/4/1000000
|
|
|
|
LD B,$0F
|
|
PAUSE:
|
|
LD C,$FF
|
|
PAUSE1:
|
|
LD A,$FF ; ADJUST THE TIME 13h IS FOR 4 MHZ
|
|
PAUSE2:
|
|
CALL RTC_BIT_DELAY ; CAUSE 36uS DELAY
|
|
DEC A ; DEC COUNTER.
|
|
JP NZ,PAUSE2 ; JUMP TO PAUSE2 IF A <> 0.
|
|
DEC C ; DEC COUNTER
|
|
JP NZ,PAUSE1 ; JUMP TO PAUSE1 IF C <> 0.
|
|
DJNZ PAUSE ; JUMP TO PAUSE IF B <> 0.
|
|
|
|
LD DE,TESTING_BIT_DELAY_OVER
|
|
LD C,09H ; CP/M write string to console call
|
|
CALL 0005H
|
|
RET
|
|
|
|
|
|
; function RTC_HELP
|
|
;
|
|
; based on following algorithm
|
|
;
|
|
; PROCEDURE help();
|
|
; BEGIN
|
|
; putln();
|
|
; putln("rtc: ",version);
|
|
; putln("rtc: Commands: (E)xit (T)ime st(A)rt (S)et (R)aw (L)oop (C)harge (N)ocharge (H)elp");
|
|
; END;
|
|
|
|
RTC_HELP
|
|
LD DE,RTC_HELP_MSG
|
|
LD C,09H ; CP/M write string to console call
|
|
CALL 0005H
|
|
RET
|
|
|
|
; function RTC_INIT
|
|
;
|
|
; Determine RTC port based on hardware platform
|
|
; and record it dynamically in code (see RTC_IN and RTC_OUT).
|
|
;
|
|
|
|
RTC_INIT:
|
|
CALL IDBIO ; Id BIOS, 1=HBIOS, 2=UBIOS
|
|
DEC A ; Test for HBIOS
|
|
JP Z,HINIT ; Do HBIOS setup
|
|
DEC A ; Test for UBIOS
|
|
JP Z,UINIT ; Do UBIOS setup
|
|
;
|
|
; Neither UNA nor RomWBW
|
|
LD DE,BIOERR ; BIOS error message
|
|
LD C,9 ; BDOS string display function
|
|
CALL BDOS ; Do it
|
|
JP 0 ; Bail out!
|
|
;
|
|
HINIT:
|
|
;
|
|
; Display RomWBW notification string
|
|
LD DE,HBTAG ; BIOS notification string
|
|
LD C,9 ; BDOS string display function
|
|
CALL BDOS ; Do it
|
|
;
|
|
; Get platform id from RomWBW HBIOS
|
|
LD B,0F1H ; HBIOS VER function 0xF1
|
|
LD C,0 ; Required reserved value
|
|
RST 08 ; Do it, L := Platform ID
|
|
LD A,L ; Move to A
|
|
;
|
|
; Assign correct port to C
|
|
LD C,PORT_SBC
|
|
LD DE,PLT_SBC
|
|
CP $01 ; SBC
|
|
JP Z,RTC_INIT2
|
|
CP $02 ; ZETA
|
|
JP Z,RTC_INIT2
|
|
CP $03 ; ZETA 2
|
|
JP Z,RTC_INIT2
|
|
;
|
|
LD C,PORT_N8
|
|
LD DE,PLT_N8
|
|
CP $04 ; N8
|
|
JP Z,RTC_INIT2
|
|
;
|
|
LD C,PORT_MK4
|
|
LD DE,PLT_MK4
|
|
CP $05 ; Mark IV
|
|
JP Z,RTC_INIT2
|
|
;
|
|
LD C,PORT_RCZ80
|
|
LD DE,PLT_RCZ80
|
|
CP $07 ; RCBus w/ Z80
|
|
JP Z,RTC_INIT2
|
|
;
|
|
LD C,PORT_RCZ180
|
|
LD DE,PLT_RCZ180
|
|
CP $08 ; RCBus w/ Z180
|
|
JP Z,RTC_INIT2
|
|
;
|
|
LD C,PORT_EZZ80
|
|
LD DE,PLT_EZZ80
|
|
CP $09 ; Easy Z80
|
|
JP Z,RTC_INIT2
|
|
;
|
|
LD C,PORT_SCZ180
|
|
LD DE,PLT_SCZ180
|
|
CP $0A ; SCZ180
|
|
JP Z,RTC_INIT2
|
|
;
|
|
LD C,PORT_DYNO
|
|
LD DE,PLT_DYNO
|
|
CP 11 ; DYNO
|
|
JP Z,RTC_INIT2
|
|
;
|
|
LD C,PORT_RCZ280
|
|
LD DE,PLT_RCZ280
|
|
CP 12 ; RCZ280
|
|
JP Z,RTC_INIT2
|
|
;
|
|
LD C,PORT_MBC
|
|
LD DE,PLT_MBC
|
|
CP 13 ; MBC
|
|
JP Z,RTC_INIT2
|
|
;
|
|
LD C,PORT_RPH
|
|
LD DE,PLT_RPH
|
|
CP 14 ; RHYOPHYRE
|
|
JP Z,RTC_INIT2
|
|
;
|
|
LD C,PORT_DUO
|
|
LD DE,PLT_DUO
|
|
CP 17 ; DUODYNE
|
|
JP Z,RTC_INIT2
|
|
;
|
|
LD C,PORT_STDZ180
|
|
LD DE,PLT_STDZ180
|
|
CP 21 ; STD Z180
|
|
JP Z,RTC_INIT2
|
|
;
|
|
|
|
; Unknown platform
|
|
LD DE,PLTERR ; BIOS error message
|
|
LD C,9 ; BDOS string display function
|
|
CALL BDOS ; Do it
|
|
JP 0 ; Bail out!
|
|
;
|
|
UINIT:
|
|
;; Display UNA notification string
|
|
;LD DE,UBTAG ; BIOS notification string
|
|
;LD C,9 ; BDOS string display function
|
|
;CALL BDOS ; Do it
|
|
;
|
|
; Notify UNA not supported at present
|
|
LD DE,UBERR ; BIOS not support message
|
|
LD C,9 ; BDOS string display function
|
|
CALL BDOS ; Do it
|
|
JP 0 ; Bail out!
|
|
|
|
RTC_INIT2:
|
|
; Record port number in code routines
|
|
LD A,C
|
|
LD (INP),A
|
|
LD (OUTP),A
|
|
;
|
|
; Display platform
|
|
LD C,9 ; BDOS string display function
|
|
CALL BDOS ; Do it
|
|
RET
|
|
|
|
;
|
|
; Identify active BIOS. RomWBW HBIOS=1, UNA UBIOS=2, else 0
|
|
;
|
|
IDBIO:
|
|
;
|
|
; Check for UNA (UBIOS)
|
|
LD A,(0FFFDH) ; fixed location of UNA API vector
|
|
CP 0C3H ; jp instruction?
|
|
JR NZ,IDBIO1 ; if not, not UNA
|
|
LD HL,(0FFFEH) ; get jp address
|
|
LD A,(HL) ; get byte at target address
|
|
CP 0FDH ; first byte of UNA push ix instruction
|
|
JR NZ,IDBIO1 ; if not, not UNA
|
|
INC HL ; point to next byte
|
|
LD A,(HL) ; get next byte
|
|
CP 0E5H ; second byte of UNA push ix instruction
|
|
JR NZ,IDBIO1 ; if not, not UNA, check others
|
|
LD A,2 ; UNA BIOS id = 2
|
|
RET ; and done
|
|
;
|
|
IDBIO1:
|
|
; Check for RomWBW (HBIOS)
|
|
LD HL,(0FFFEH) ; HL := HBIOS ident location
|
|
LD A,'W' ; First byte of ident
|
|
CP (HL) ; Compare
|
|
JR NZ,IDBIO2 ; Not HBIOS
|
|
INC HL ; Next byte of ident
|
|
LD A,~'W' ; Second byte of ident
|
|
CP (HL) ; Compare
|
|
JR NZ,IDBIO2 ; Not HBIOS
|
|
LD A,1 ; HBIOS BIOS id = 1
|
|
RET ; and done
|
|
;
|
|
IDBIO2:
|
|
; No idea what this is
|
|
XOR A ; Setup return value of 0
|
|
RET ; and done
|
|
|
|
|
|
; function RTC_TOP_LOOP
|
|
;
|
|
; based on following algorithm
|
|
;
|
|
; PROCEDURE toploop();
|
|
; var
|
|
; err,i,n,fd : int;
|
|
; BEGIN
|
|
; putln();
|
|
; help();
|
|
; rtc_reset_on();
|
|
; hold(100);
|
|
; test_bit_delay();
|
|
; rtc_charge_disable();
|
|
; putln("rtc: trickle charger disabled.");
|
|
; loop
|
|
; put("rtc>");
|
|
; gets(line);
|
|
; if line = "exit" then
|
|
; putln("Bye.");
|
|
; exit(0);
|
|
; elsif line = "charge" then
|
|
; putln("Trickle charger enabled.");
|
|
; rtc_charge_enable();
|
|
; elsif line = "nocharge" then
|
|
; putln("Trickle charger disabled.");
|
|
; rtc_charge_disable();
|
|
; elsif line = "start" then
|
|
; rtc_restart();
|
|
; putln("Restarting RTC");
|
|
; elsif line = "t" then
|
|
; rtc_get_time(line);
|
|
; putln("Current time: ",line);
|
|
; elsif line = "raw" then
|
|
; putln();
|
|
; putln("Raw read loop, hit any key to stop...");
|
|
; while read(0,@n,1 + RD_NOWAIT) = 0 loop
|
|
; put(#13,"sec=",hexstr(rtc_read(0))^);
|
|
; put(" min=",hexstr(rtc_read(1))^);
|
|
; hold(500);
|
|
; end loop;
|
|
; elsif line = "loop" then
|
|
; putln();
|
|
; putln("Clock loop, hit any key to stop...");
|
|
; while read(0,@n,1 + RD_NOWAIT) = 0 loop
|
|
; rtc_get_time(line);
|
|
; put(#13,line);
|
|
; hold(200);
|
|
; end loop;
|
|
; elsif line = "set" then
|
|
; putln("Setting RTC time to 96-02-18 19:43:00");
|
|
; rtc_set_now();
|
|
; elsif (line = "help") or (line = "?") then
|
|
; help();
|
|
; elsif length(line) <> 0 then
|
|
; putln("You typed: """,line,"""");
|
|
; end;
|
|
; end loop;
|
|
; END toploop;
|
|
; Note:above code is not fully in sync with current menu code
|
|
|
|
RTC_TOP_LOOP:
|
|
CALL RTC_RESET_ON
|
|
CALL RTC_BIT_DELAY
|
|
CALL RTC_BIT_DELAY
|
|
CALL RTC_BIT_DELAY
|
|
|
|
LD A,(FCB+1) ; If there a command line tail
|
|
CP '/' ; get the command and feed it
|
|
LD A,(FCB+2) ; into the input stream
|
|
JR Z,RTC_UCL
|
|
|
|
LD DE,CRLF_MSG
|
|
LD C,09H ; CP/M write string to console call
|
|
CALL 0005H
|
|
|
|
CALL RTC_HELP
|
|
|
|
RTC_TOP_LOOP_1:
|
|
LD DE,RTC_TOP_LOOP1_PROMPT
|
|
LD C,09H ; CP/M write string to console call
|
|
CALL 0005H
|
|
|
|
LD C,01H ; CP/M console input call
|
|
CALL 0005H
|
|
RTC_UCL:
|
|
AND %01011111 ; handle lower case responses to menu
|
|
|
|
CP 'L'
|
|
JP Z,RTC_TOP_LOOP_LOOP
|
|
|
|
CP 'R'
|
|
JP Z,RTC_TOP_LOOP_RAW
|
|
|
|
CP 'G'
|
|
JP Z,RTC_TOP_LOOP_GET
|
|
|
|
CP 'P'
|
|
JP Z,RTC_TOP_LOOP_PUT
|
|
|
|
CP 'E'
|
|
; JP Z,RTC_TOP_LOOP_EXIT
|
|
RET Z
|
|
|
|
CP 'H'
|
|
JP Z,RTC_TOP_LOOP_HELP
|
|
|
|
CP 'D'
|
|
JP Z,RTC_TOP_LOOP_DELAY
|
|
|
|
CP 'B'
|
|
JP Z,RTC_TOP_LOOP_BOOT
|
|
|
|
CP 'W'
|
|
JP Z,RTC_TOP_LOOP_WARMSTART
|
|
|
|
CP 'C'
|
|
JP Z,RTC_TOP_LOOP_CHARGE
|
|
|
|
CP 'N'
|
|
JP Z,RTC_TOP_LOOP_NOCHARGE
|
|
|
|
CP 'A'
|
|
JP Z,RTC_TOP_LOOP_START
|
|
|
|
CP 'S'
|
|
JP Z,RTC_TOP_LOOP_SET
|
|
|
|
CP 'I'
|
|
JP Z,RTC_TOP_LOOP_INIT
|
|
|
|
CP 'T'
|
|
JP Z,RTC_TOP_LOOP_TIME
|
|
|
|
LD DE,CRLF_MSG
|
|
LD C,09H ; CP/M write string to console call
|
|
CALL 0005H
|
|
|
|
JR RTC_TOP_LOOP_1
|
|
|
|
;RTC_TOP_LOOP_EXIT:
|
|
; RET
|
|
|
|
RTC_TOP_LOOP_HELP:
|
|
CALL RTC_HELP
|
|
JP RTC_TOP_LOOP_1
|
|
|
|
RTC_TOP_LOOP_DELAY:
|
|
CALL RTC_TEST_BIT_DELAY
|
|
JP RTC_TOP_LOOP_1
|
|
|
|
RTC_TOP_LOOP_BOOT:
|
|
LD DE,BOOTMSG ; BOOT message
|
|
LD C,9 ; BDOS string display function
|
|
CALL BDOS ; Do it
|
|
; WAIT FOR MESSAGE TO BE DISPLAYED
|
|
LD HL,10000
|
|
DELAY_LOOP: ; LOOP IS 26TS
|
|
DEC HL ; 6TS
|
|
LD A,H ; 4TS
|
|
OR L ; 4TS
|
|
JR NZ,DELAY_LOOP ; 12TS
|
|
; RESTART SYSTEM FROM ROM BANK 0, ADDRESS $0000
|
|
LD B,BF_SYSRESET ; SYSTEM RESTART
|
|
LD C,BF_SYSRES_COLD ; COLD START
|
|
CALL $FFF0 ; CALL HBIOS
|
|
|
|
|
|
RTC_TOP_LOOP_WARMSTART:
|
|
LD B,BF_SYSRESET ; SYSTEM RESTART
|
|
LD C,BF_SYSRES_WARM ; WARM START
|
|
CALL $FFF0 ; CALL HBIOS
|
|
|
|
RTC_TOP_LOOP_CHARGE:
|
|
LD DE,RTC_TOP_LOOP1_CHARGE
|
|
LD C,09H ; CP/M write string to console call
|
|
CALL 0005H
|
|
CALL RTC_CHARGE_ENABLE
|
|
LD A,(FCB+1) ; If we came from the
|
|
CP '/' ; command line
|
|
RET Z ; exit back to CP/M
|
|
JP RTC_TOP_LOOP_1
|
|
|
|
RTC_TOP_LOOP_NOCHARGE:
|
|
LD DE,RTC_TOP_LOOP1_NOCHARGE
|
|
LD C,09H ; CP/M write string to console call
|
|
CALL 0005H
|
|
CALL RTC_CHARGE_DISABLE
|
|
LD A,(FCB+1) ; If we came from the
|
|
CP '/' ; command line
|
|
RET Z ; exit back to CP/M
|
|
JP RTC_TOP_LOOP_1
|
|
|
|
RTC_TOP_LOOP_START:
|
|
LD DE,RTC_TOP_LOOP1_START
|
|
LD C,09H ; CP/M write string to console call
|
|
CALL 0005H
|
|
CALL RTC_RESTART
|
|
JP RTC_TOP_LOOP_1
|
|
|
|
RTC_TOP_LOOP_SET:
|
|
LD DE,RTC_TOP_LOOP1_SET
|
|
LD C,09H ; CP/M write string to console call
|
|
CALL 0005H
|
|
CALL RTC_SET_NOW
|
|
JP RTC_TOP_LOOP_1
|
|
|
|
RTC_TOP_LOOP_INIT:
|
|
LD DE,RTC_TOP_LOOP1_INIT
|
|
LD C,09H ; CP/M write string to console call
|
|
CALL 0005H
|
|
CALL RTC_INIT_NOW
|
|
JP RTC_TOP_LOOP_1
|
|
|
|
RTC_TOP_LOOP_TIME:
|
|
LD DE,RTC_TOP_LOOP1_TIME
|
|
LD C,09H ; CP/M write string to console call
|
|
CALL 0005H
|
|
CALL RTC_GET_TIME
|
|
LD DE,RTC_PRINT_BUFFER
|
|
LD C,09H ; CP/M write string to console call
|
|
CALL 0005H
|
|
LD A,(FCB+1) ; If we came from the
|
|
CP '/' ; command line
|
|
RET Z ; exit back to CP/M
|
|
JP RTC_TOP_LOOP_1
|
|
|
|
RTC_TOP_LOOP_RAW:
|
|
LD DE,RTC_TOP_LOOP1_RAW
|
|
LD C,09H ; CP/M write string to console call
|
|
CALL 0005H
|
|
RTC_TOP_LOOP_RAW1:
|
|
|
|
; { Read seconds }
|
|
LD D,$00 ; seconds register in DS1302
|
|
CALL RTC_READ ; read value from DS1302, value is in Reg C
|
|
|
|
; digit 16
|
|
LD A,C ; put value output in Reg C into accumulator
|
|
RLC A
|
|
RLC A
|
|
RLC A
|
|
RLC A
|
|
AND $07
|
|
ADD A,'0'
|
|
LD (RTC_PRINT_BUFFER+15),A
|
|
|
|
; digit 17
|
|
LD A,C ; put value output in Reg C into accumulator
|
|
AND $0F
|
|
ADD A,'0'
|
|
LD (RTC_PRINT_BUFFER+16),A
|
|
|
|
; { Read minutes }
|
|
|
|
LD D,$01 ; minutes register in DS1302
|
|
CALL RTC_READ ; read value from DS1302, value is in Reg C
|
|
|
|
; digit 13
|
|
LD A,C ; put value output in Reg C into accumulator
|
|
RLC A
|
|
RLC A
|
|
RLC A
|
|
RLC A
|
|
AND $07
|
|
ADD A,'0'
|
|
LD (RTC_PRINT_BUFFER+12),A
|
|
|
|
; digit 14
|
|
LD A,C ; put value output in Reg C into accumulator
|
|
AND $0F
|
|
ADD A,'0'
|
|
LD (RTC_PRINT_BUFFER+13),A
|
|
|
|
; digit 15
|
|
LD A,':'
|
|
LD (RTC_PRINT_BUFFER+14),A
|
|
|
|
; digits 1-12 and 18-20 are spaces
|
|
LD A,' ' ; space
|
|
LD (RTC_PRINT_BUFFER+19),A
|
|
LD (RTC_PRINT_BUFFER+18),A
|
|
LD (RTC_PRINT_BUFFER+17),A
|
|
LD (RTC_PRINT_BUFFER+11),A
|
|
LD (RTC_PRINT_BUFFER+10),A
|
|
LD (RTC_PRINT_BUFFER+09),A
|
|
LD (RTC_PRINT_BUFFER+08),A
|
|
LD (RTC_PRINT_BUFFER+07),A
|
|
LD (RTC_PRINT_BUFFER+06),A
|
|
LD (RTC_PRINT_BUFFER+05),A
|
|
LD (RTC_PRINT_BUFFER+04),A
|
|
LD (RTC_PRINT_BUFFER+03),A
|
|
LD (RTC_PRINT_BUFFER+02),A
|
|
LD (RTC_PRINT_BUFFER+01),A
|
|
LD (RTC_PRINT_BUFFER+00),A
|
|
|
|
LD DE,RTC_PRINT_BUFFER
|
|
LD C,09H ; CP/M write string to console call
|
|
CALL 0005H
|
|
|
|
LD C,01H ; CP/M console input call
|
|
CALL 0005H
|
|
|
|
CP ' ' ; space
|
|
JP Z,RTC_TOP_LOOP_RAW1
|
|
|
|
JP RTC_TOP_LOOP_1
|
|
|
|
RTC_TOP_LOOP_LOOP:
|
|
LD DE,RTC_TOP_LOOP1_LOOP
|
|
LD C,09H ; CP/M write string to console call
|
|
CALL 0005H
|
|
|
|
RTC_TOP_LOOP_LOOP1:
|
|
CALL RTC_GET_TIME
|
|
|
|
LD DE,RTC_PRINT_BUFFER
|
|
LD C,09H ; CP/M write string to console call
|
|
CALL 0005H
|
|
|
|
LD C,01H ; CP/M console input call
|
|
CALL 0005H
|
|
|
|
CP ' '
|
|
JP Z,RTC_TOP_LOOP_LOOP1
|
|
|
|
JP RTC_TOP_LOOP_1
|
|
|
|
RTC_TOP_LOOP_PUT:
|
|
LD A,$01 ; set PUT as true
|
|
LD (GET_PUT),A
|
|
RTC_TOP_LOOP_GET:
|
|
LD DE,RTC_TOP_LOOP1_GET
|
|
LD C,09H ; CP/M write string to console call
|
|
CALL 0005H
|
|
|
|
CALL HEXIN ; read NVRAM address
|
|
LD (PUT_ADR),A ; store for possible PUT later
|
|
|
|
; { Read NVRAM address }
|
|
LD D,A ; seconds register in DS1302
|
|
CALL RTC_READ ; read value from DS1302, value is in Reg C
|
|
|
|
; first digit
|
|
LD A,C ; put value output in Reg C into accumulator
|
|
RLC A
|
|
RLC A
|
|
RLC A
|
|
RLC A
|
|
AND $0F
|
|
CP 0AH ;TEST FOR NUMERIC & convert to ASCII
|
|
JR C,NUM1 ;if not ALPHA, its numeric and skip
|
|
ADD A,$07
|
|
|
|
NUM1: ADD A,'0'
|
|
LD (RTC_GET_BUFFER),A
|
|
|
|
; second digit
|
|
LD A,C ; put value output in Reg C into accumulator
|
|
AND $0F
|
|
CP 0AH ;TEST FOR NUMERIC & convert to ASCII
|
|
JR C,NUM2 ;if not ALPHA, its numeric and skip
|
|
ADD A,$07
|
|
|
|
NUM2: ADD A,'0'
|
|
LD (RTC_GET_BUFFER+1),A
|
|
|
|
LD DE,CRLF_MSG
|
|
LD C,09H ; CP/M write string to console call
|
|
CALL 0005H
|
|
|
|
LD DE,RTC_GET_BUFFER
|
|
LD C,09H ; CP/M write string to console call
|
|
CALL 0005H
|
|
|
|
LD A,(GET_PUT) ; check if GET or PUT mode
|
|
CP $00
|
|
JP Z,RTC_GET_PUT_EXIT ; if GET mode, exit
|
|
|
|
LD DE,RTC_TOP_LOOP1_PUT
|
|
LD C,09H ; CP/M write string to console call
|
|
CALL 0005H
|
|
|
|
; { Write NVRAM address }
|
|
|
|
CALL RTC_WR_UNPROTECT
|
|
|
|
CALL HEXIN ; read NVRAM address
|
|
LD E,A ; new data for NVRAM register in DS1302
|
|
LD A,(PUT_ADR)
|
|
LD D,A ; load address from before
|
|
|
|
CALL RTC_WRITE ; read value from DS1302, value is in Reg C
|
|
|
|
CALL RTC_WR_PROTECT
|
|
|
|
RTC_GET_PUT_EXIT:
|
|
LD A,$00 ; reset GET mode
|
|
LD (GET_PUT),A
|
|
JP RTC_TOP_LOOP_1
|
|
|
|
;
|
|
; Text Strings
|
|
;
|
|
|
|
MSG:
|
|
.TEXT "Start RTC Program"
|
|
CRLF_MSG:
|
|
.DB 0Ah, 0Dh ; line feed and carriage return
|
|
.DB "$" ; Line terminator
|
|
|
|
TESTING_BIT_DELAY_MSG:
|
|
.DB 0Ah, 0Dh ; line feed and carriage return
|
|
.TEXT "Testing bit delay. Successful test is ~43 sec."
|
|
.DB 0Ah, 0Dh ; line feed and carriage return
|
|
.TEXT "Start clock and press space bar."
|
|
.DB 0Ah, 0Dh ; line feed and carriage return
|
|
.DB "$" ; Line terminator
|
|
|
|
TESTING_BIT_DELAY_OVER:
|
|
.DB 0Ah, 0Dh ; line feed and carriage return
|
|
.TEXT "Test complete. Stop clock."
|
|
.DB 0Ah, 0Dh ; line feed and carriage return
|
|
.DB "$" ; Line terminator
|
|
|
|
RTC_HELP_MSG:
|
|
.DB 0Ah, 0Dh ; line feed and carriage return
|
|
.TEXT "RTC: Version 1.9"
|
|
.DB 0Ah, 0Dh ; line feed and carriage return
|
|
.TEXT "Commands: E)xit T)ime st(A)rt S)et R)aw L)oop C)harge N)ocharge D)elay I)nit G)et P)ut B)oot W)arm-start H)elp"
|
|
.DB 0Ah, 0Dh ; line feed and carriage return
|
|
.DB "$" ; Line terminator
|
|
|
|
RTC_TOP_LOOP1_PROMPT:
|
|
.DB 0Ah, 0Dh ; line feed and carriage return
|
|
.TEXT "RTC>"
|
|
.DB "$" ; Line terminator
|
|
|
|
RTC_TOP_LOOP1_CHARGE:
|
|
.DB 0Ah, 0Dh ; line feed and carriage return
|
|
.TEXT "Trickle charger enabled."
|
|
.DB 0Ah, 0Dh ; line feed and carriage return
|
|
.DB "$" ; Line terminator
|
|
|
|
RTC_TOP_LOOP1_NOCHARGE:
|
|
.DB 0Ah, 0Dh ; line feed and carriage return
|
|
.TEXT "Trickle charger disabled."
|
|
.DB 0Ah, 0Dh ; line feed and carriage return
|
|
.DB "$" ; Line terminator
|
|
|
|
RTC_TOP_LOOP1_START:
|
|
.DB 0Ah, 0Dh ; line feed and carriage return
|
|
.TEXT "Restart RTC."
|
|
.DB 0Ah, 0Dh ; line feed and carriage return
|
|
.DB "$" ; Line terminator
|
|
|
|
RTC_TOP_LOOP1_TIME:
|
|
.DB 0Ah, 0Dh ; line feed and carriage return
|
|
.TEXT "Current time: "
|
|
.DB "$" ; Line terminator
|
|
|
|
RTC_TOP_LOOP1_RAW:
|
|
.DB 0Ah, 0Dh ; line feed and carriage return
|
|
.TEXT "Raw read Loop. Press SPACE BAR for next."
|
|
.DB 0Ah, 0Dh ; line feed and carriage return
|
|
.DB "$" ; Line terminator
|
|
|
|
RTC_TOP_LOOP1_LOOP:
|
|
.DB 0Ah, 0Dh ; line feed and carriage return
|
|
.TEXT "Clock Loop. Press SPACE BAR for next."
|
|
.DB 0Ah, 0Dh ; line feed and carriage return
|
|
.DB "$" ; Line terminator
|
|
|
|
RTC_TOP_LOOP1_SET:
|
|
.DB 0Ah, 0Dh ; line feed and carriage return
|
|
.TEXT "Set RTC time."
|
|
.DB 0Ah, 0Dh ; line feed and carriage return
|
|
.DB "$" ; Line terminator
|
|
|
|
RTC_TOP_LOOP1_INIT:
|
|
.DB 0Ah, 0Dh ; line feed and carriage return
|
|
.TEXT "Init date/time."
|
|
.DB 0Ah, 0Dh ; line feed and carriage return
|
|
.DB "$" ; Line terminator
|
|
|
|
RTC_TOP_LOOP1_GET:
|
|
.DB 0Ah, 0Dh ; line feed and carriage return
|
|
.TEXT "Get NVRAM addr:"
|
|
.DB "$" ; Line terminator
|
|
|
|
RTC_TOP_LOOP1_PUT:
|
|
.DB 0Ah, 0Dh ; line feed and carriage return
|
|
.TEXT "NVRAM data:"
|
|
.DB "$" ; Line terminator
|
|
|
|
RTC_TOP_LOOP1_INIT_SECONDS:
|
|
.DB 0Ah, 0Dh ; line feed and carriage return
|
|
.TEXT "SECONDS:"
|
|
.DB "$" ; Line terminator
|
|
|
|
RTC_TOP_LOOP1_INIT_MINUTES:
|
|
.DB 0Ah, 0Dh ; line feed and carriage return
|
|
.TEXT "MINUTES:"
|
|
.DB "$" ; Line terminator
|
|
|
|
RTC_TOP_LOOP1_INIT_HOURS:
|
|
.DB 0Ah, 0Dh ; line feed and carriage return
|
|
.TEXT "HOURS:"
|
|
.DB "$" ; Line terminator
|
|
|
|
RTC_TOP_LOOP1_INIT_DATE:
|
|
.DB 0Ah, 0Dh ; line feed and carriage return
|
|
.TEXT "DATE:"
|
|
.DB "$" ; Line terminator
|
|
|
|
RTC_TOP_LOOP1_INIT_MONTH:
|
|
.DB 0Ah, 0Dh ; line feed and carriage return
|
|
.TEXT "MONTH:"
|
|
.DB "$" ; Line terminator
|
|
|
|
RTC_TOP_LOOP1_INIT_DAY:
|
|
.DB 0Ah, 0Dh ; line feed and carriage return
|
|
.TEXT "DAY:"
|
|
.DB "$" ; Line terminator
|
|
|
|
RTC_TOP_LOOP1_INIT_YEAR:
|
|
.DB 0Ah, 0Dh ; line feed and carriage return
|
|
.TEXT "YEAR:"
|
|
.DB "$" ; Line terminator
|
|
|
|
RTC_PRINT_BUFFER:
|
|
.FILL 20,0 ; Buffer for formatted date & time to print
|
|
.DB 0Ah, 0Dh ; line feed and carriage return
|
|
.DB "$" ; line terminator
|
|
|
|
RTC_GET_BUFFER:
|
|
.FILL 2,0 ; Buffer for formatted NVRAM data to print
|
|
.DB 0Ah, 0Dh ; line feed and carriage return
|
|
.DB "$" ; line terminator
|
|
|
|
BIOERR .TEXT "\r\nUnknown BIOS, aborting...\r\n$"
|
|
PLTERR .TEXT "\r\n\r\nUnknown/unsupported hardware platform, aborting...\r\n$"
|
|
UBERR .TEXT "\r\nUNA UBIOS is not currently supported, aborting...\r\n$"
|
|
HBTAG .TEXT "RomWBW HBIOS$"
|
|
UBTAG .TEXT "UNA UBIOS"
|
|
BOOTMSG .TEXT "\r\n\r\nRebooting...$"
|
|
PLT_SBC .TEXT ", SBC/Zeta RTC Latch Port 0x70\r\n$"
|
|
PLT_N8 .TEXT ", N8 RTC Latch Port 0x88\r\n$"
|
|
PLT_MK4 .TEXT ", Mark 4 RTC Latch Port 0x8A\r\n$"
|
|
PLT_RCZ80 .TEXT ", RCBus Z80 RTC Module Latch Port 0xC0\r\n$"
|
|
PLT_RCZ180 .TEXT ", RCBus Z180 RTC Module Latch Port 0x0C\r\n$"
|
|
PLT_EZZ80 .TEXT ", Easy Z80 RTC Module Latch Port 0xC0\r\n$"
|
|
PLT_SCZ180 .TEXT ", SC Z180 RTC Module Latch Port 0x0C\r\n$"
|
|
PLT_DYNO .TEXT ", DYNO RTC Module Latch Port 0x0C\r\n$"
|
|
PLT_RCZ280 .TEXT ", RCBus Z280 RTC Module Latch Port 0xC0\r\n$"
|
|
PLT_MBC .TEXT ", MBC RTC Latch Port 0x70\r\n$"
|
|
PLT_RPH .TEXT ", RHYOPHYRE RTC Latch Port 0x84\r\n$"
|
|
PLT_DUO .TEXT ", DUODYNE RTC Latch Port 0x70\r\n$"
|
|
PLT_STDZ180 .TEXT ", STD Z180 RTC Module latch port 0x84\r\n$"
|
|
|
|
;
|
|
; Generic FOR-NEXT loop algorithm
|
|
;
|
|
; LD A,$00 ; set A=0 index counter of FOR loop
|
|
;FOR_LOOP:
|
|
; PUSH AF ; save accumulator as it is the index counter in FOR loop
|
|
; { contents of FOR loop here } ; setup RTC with RST and RD high, SCLK low
|
|
; POP AF ; recover accumulator as it is the index counter in FOR loop
|
|
; INC A ; increment A in FOR loop (A=A+1)
|
|
; CP $08 ; is A < $08 ?
|
|
; JP NZ,FOR_LOOP ; No, do FOR loop again
|
|
; RET ; Yes, end function and return. Read RTC value is in C
|
|
|
|
YEAR .DB $18
|
|
MONTH .DB $11
|
|
DATE .DB $08
|
|
HOURS .DB $00
|
|
MINUTES .DB $00
|
|
SECONDS .DB $00
|
|
DAY .DB $05
|
|
GET_PUT .DB $00
|
|
|
|
PUT_ADR .DB 0
|
|
|
|
.END
|
|
|
|
|