diff --git a/Source/Apps/Build.cmd b/Source/Apps/Build.cmd index c9732eb6..d9c389ff 100644 --- a/Source/Apps/Build.cmd +++ b/Source/Apps/Build.cmd @@ -21,6 +21,7 @@ call :asm RTC || goto :eof call :asm Timer || goto :eof call :asm180 IntTest || goto :eof call :asm rtcds7 || goto :eof +call :asm rtchb || goto :eof zx Z80ASM -SYSGEN/F diff --git a/Source/Apps/rtchb.asm b/Source/Apps/rtchb.asm new file mode 100644 index 00000000..9003f9d9 --- /dev/null +++ b/Source/Apps/rtchb.asm @@ -0,0 +1,220 @@ +;================================================================================================== +; GENERIC HBIOS DATE AND TIME +;================================================================================================== +; +; HBIOS FORMAT = YYMMDDHHMMSS +; + .ORG 100H +; +; + LD B,$20 ; READ CLOCK DATA INTO BUFFER + LD HL,HBC_BUF ; DISPLAY TIME AND DATE FROM BUFFER + RST 08 +; +#IF (0) + LD A,6 + LD DE,HBC_BUF ; DISLAY DATA READ +; CALL PRTHEXBUF + CALL NEWLINE +#ENDIF +; + CALL HBC_DISP + RET + +HBC_BUF .FILL 6,0 +; +;----------------------------------------------------------------------------- +; DISPLAY CLOCK INFORMATION FROM DATA STORED IN BUFFER +; +HBC_DISP: + LD HL,HBC_CLKTBL +HBC_CLP:LD C,(HL) + INC HL + LD D,(HL) + CALL HBC_BCD + INC HL + LD A,(HL) + OR A + RET Z + CALL COUT + INC HL + JR HBC_CLP + RET +; +HBC_CLKTBL: + .DB 02H, 00111111B, '/' + .DB 01H, 00011111B, '/' + .DB 00H, 11111111B, ' ' + .DB 03H, 00011111B, ':' + .DB 04H, 01111111B, ':' + .DB 05H, 01111111B, 00H +; +HBC_BCD:PUSH HL + LD HL,HBC_BUF ; READ VALUE FROM + LD B,0 ; BUFFER, INDEXED BY A + ADD HL,BC + LD A,(HL) + AND D ; MASK OFF UNNEEDED + SRL A + SRL A + SRL A + SRL A + ADD A,30H + CALL COUT + LD A,(HL) + AND 00001111B + ADD A,30H + CALL COUT + POP HL + RET +; +;----------------------------------------------------------------------------- +; DISPLAY ERROR + +HBC_ERR: + PUSH HL + LD HL,HBC_FAIL + JR HBC_PRTERR +; +HBC_PRTERR: + CALL PRTSTR + CALL NEWLINE + POP HL + RET +; +HBC_FAIL .DB "ERROR$" +; +;----------------------------------------------------------------------------- +; GENERIC CP/M ROUTINES +; +BDOS .EQU 5 ;ENTRY BDOS +BS .EQU 8 ;BACKSPACE +TAB .EQU 9 ;TABULATOR +LF .EQU 0AH ;LINE-FEED +CR .EQU 0DH ;CARRIAGE-RETURN +; +; OUTPUT TEXT AT HL +; +PRTSTR: LD A,(HL) + OR A + RET Z + CALL PRINP + INC HL + JR PRTSTR +; +;Output WORD +;*********** +; +;PARAMETER: Entry WORD IN HL +;********* +; +OUTW: LD A,H + CALL OUTB + LD A,L + CALL OUTB + RET +; +;Output BYTE +;*********** +; +;PARAMETER: Entry BYTE IN A +;********* +; +OUTB: PUSH AF + RRCA + RRCA + RRCA + RRCA + AND 0FH + CALL HBTHE ;Change Half-BYTE + POP AF + AND 0FH + CALL HBTHE + RET +; +;Output HALF-BYTE +;**************** +; +;PARAMETER: Entry Half-BYTE IN A (BIT 0 - 3) +;********* +; +HBTHE: CP 0AH + JR C,HBTHE1 + ADD A,7 ;Character to Letter +HBTHE1: ADD A,30H + LD E,A + CALL PCHAR + RET +; +; +;Output on Screen +;**************** +; +PRBS: LD E,BS + CALL PCHAR + RET +; +;Output CR+LF on Screen +;********************** +; +NEWLINE: +CRLF: LD E,CR + CALL PCHAR + LD E,LF + CALL PCHAR + RET +; +;Output ASCII-Character +;********************** +; +COUT: +PRINP: PUSH AF + PUSH DE + LD E,A + CALL PCHAR + POP DE + POP AF + RET +; +;CALL BDOS with Register Save +;**************************** +; +INCHA: LD C,1 ;INPUT CHARACTER TO A + JR BDO +PCHAR: LD C,2 ;PRINT CHARACTER IN E + JR BDO +PSTRIN: LD C,9 ;PRINT STRING + JR BDO +INBUFF: LD C,10 ;READ CONSOLE-BUFFER + JR BDO +CSTS: LD C,11 ;CONSOLE-STATUS + JR BDO +OPEN: LD C,15 ;OPEN FILE + JR BDO +CLOSE: LD C,16 ;CLOSE FILE + JR BDO +DELETE: LD C,19 ;DELETE FILE + JR BDO +READS: LD C,20 ;READ SEEK + JR BDO +WRITES: LD C,21 ;WRITE SEEK + JR BDO +MAKE: LD C,22 ;MAKE FILE + JR BDO +SETDMA: LD C,26 ;SET DMA-ADDRESS +BDO: PUSH HL + PUSH DE + PUSH BC + PUSH IX + PUSH IY + CALL BDOS + POP IY + POP IX + POP BC + POP DE + POP HL + RET +; + .END + + \ No newline at end of file diff --git a/Source/HBIOS/ds7rtc.asm b/Source/HBIOS/ds7rtc.asm new file mode 100644 index 00000000..ab105c9b --- /dev/null +++ b/Source/HBIOS/ds7rtc.asm @@ -0,0 +1,332 @@ +;================================================================================================== +; DS1307 PCF I2C CLOCK DRIVER +; +; LABELS STARTING WITH PCF ARE REFERENCING THE PCF8584 LIBRARY +; +;================================================================================================== +; +DS7_OUT .EQU 10000000B ; SELECT SQUARE WAVE FUNCTION +DS7_SQWE .EQU 00010000B ; ENABLE SQUARE WAVE OUTPUT +DS7_RATE .EQU 00000000B ; SET 1HZ OUPUT +; +DS7_DS1307 .EQU 11010000B ; DEVICE IDENTIFIER +DS7_W .EQU 00000000B ; DEVICE WRITE +DS7_R .EQU 00000001B ; DEVICE READ +; +DS7_READ .EQU (DS7_DS1307 | DS7_R) ; READ +DS7_WRITE .EQU (DS7_DS1307 | DS7_W) ; WRITE +; +DS7_CTL .EQU (DS7_OUT | DS7_SQWE | DS7_RATE) +; +;----------------------------------------------------------------------------- +; DS1307 INITIALIZATION +; +; ASSUMES PCF8584 I2C HAS ALREADY BEEN INITIALIZED +; CHECKS IF OSCILLATOR IS RUNNING. IF IT ISN'T THE +; CLOCK IS RESTARTED WITH DEFAULT VALUES. +; +; DRIVER WILL NOT BE INSTALLED AS PART OF HBIOS IF +; THERE IS ALREADY AND EXISTING RTC INSTALLED. +; +; 12HR MODE IS CURRENTLY ASSUMED +; +DS7RTC_INIT: + PRTS("DS1307: $") ; ANNOUNCE DRIVER +; + CALL DS7_RDC ; READ CLOCK DATA + LD HL,DS7_BUF ; IF NOT RUNNING OR + BIT 7,(HL) ; INVALID, RESTART + JR Z,DS7_CSET ; AND RESET. + CALL DS7_SETC + CALL DS7_RDC ; READ AND DISPLAY +DS7_CSET: + CALL DS7_DISP ; DATE AND TIME +; + LD A,(RTC_DISPACT) ; CHECK RTC DISPATCHER STATUS. + OR A ; RETURN NOW IF WE ALREADY HAVE + RET NZ ; A PRIMARY RTC INSTALLED. +; + LD BC,DS7_DISPATCH ; SETUP CLOCK HBIOS DISATCHER + CALL RTC_SETDISP +; +; CALL DS7_GETTIM +; + XOR A ; SIGNAL SUCCESS + RET +; +;----------------------------------------------------------------------------- +; DS1307 HBIOS DISPATCHER +; +; A: RESULT (OUT), 0=OK, Z=OK, NZ=ERROR +; B: FUNCTION (IN) +; +DS7_DISPATCH: + LD A, B ; GET REQUESTED FUNCTION + AND $0F ; ISOLATE SUB-FUNCTION + JP Z, DS7_GETTIM ; GET TIME + DEC A + JP Z, DS7_SETTIM ; SET TIME + DEC A + JP Z, DS7_GETBYT ; GET NVRAM BYTE VALUE + DEC A + JP Z, DS7_SETBYT ; SET NVRAM BYTE VALUE + DEC A + JP Z, DS7_GETBLK ; GET NVRAM DATA BLOCK VALUE + DEC A + JP Z, DS7_SETBLK ; SET NVRAM DATA BLOCK VALUE + DEC A + JP Z, DS7_GETALM ; GET ALARM + DEC A + JP Z, DS7_SETALM ; SET ALARM + DEC A + JP Z, DS7_DEVICE ; REPORT RTC DEVICE INFO + CALL SYSCHK + LD A,ERR_NOFUNC + OR A + RET +; +;----------------------------------------------------------------------------- +; DS1307 GET TIME +; +; HL POINT TO A BUFFER TO STORE THE CURRENT TIME AND DATE IN. +; THE TIME AND DATE INFORMATION MUST BE TRANSLATED TO THE +; HBIOS FORMAT AND COPIED FROM THE HBIOS DRIVER BANK TO +; CALLER INVOKED BANK. +; +; HBIOS FORMAT = YYMMDDHHMMSS +; DS1307 FORMAT = SSMMHH..DDMMYY.. +; +DS7_GETTIM: + PUSH HL ; SAVE DESTINATION + CALL DS7_RDC ; READ THE CLOCK INTO THE BUFFER +; + LD HL,DS7_BUF+2 + LD DE,DS7_BUF+3 ; TRANSLATE + LD B,3 ; FORMAT +DS7_GT0:LD A,(HL) + LD (DE),A + INC DE + LD A,(DE) + LD (HL),A + DEC HL + DJNZ DS7_GT0 +; + INC HL ; POINT TO SECONDS + RES 7,(HL) ; REMOVE OSCILLATOR BIT + POP DE ; HL POINT TO SOURCE +; ; DE POINT TO DESTINATION +#IF (0) + PUSH HL + PUSH DE + EX DE,HL + LD A,6 + CALL PRTHEXBUF + POP DE + POP HL +#ENDIF +; + LD A,BID_BIOS ; COPY FROM BIOS BANK + LD (HB_SRCBNK),A ; SET IT + LD A, (HB_INVBNK) ; COPY TO CURRENT USER BANK + LD (HB_DSTBNK),A ; SET IT + LD BC, 6 ; LENGTH IS 6 BYTES +#IF (INTMODE == 1) + DI +#ENDIF + CALL HB_BNKCPY ; COPY THE CLOCK DATA +#IF (INTMODE == 1) + EI +#ENDIF + XOR A ; SIGNAL SUCCESS + RET +; +;----------------------------------------------------------------------------- +; DS1307 SET TIME +; +DS7_SETTIM: +; + RET +; +;----------------------------------------------------------------------------- +; FUNCTIONS THAT ARE NOT AVAILABLE OR IMPLEMENTED +; +DS7_GETBYT: +DS7_SETBYT: +DS7_GETBLK: +DS7_SETBLK: +DS7_SETALM +DS7_GETALM + CALL SYSCHK + LD A,ERR_NOTIMPL + OR A + RET +;----------------------------------------------------------------------------- +; REPORT RTC DEVICE INFO +; +; THE I2C BUS ADDRESS IS REPORTED RATHER THAN THE I2C PORT ADDRESS. +; ONLY ONE CLOCK CAN BE INSTALLED IN HBIOS SO DEVICE NUMBER IS ALWAYS 0. +; +DS7_DEVICE: + LD D,RTCDEV_DS7 ; D := DEVICE TYPE + LD E,0 ; E := PHYSICAL DEVICE NUMBER + LD H,0 ; H := 0, DRIVER HAS NO MODES + LD L,DS7_DS1307 ; L := BUS ADDRESS + XOR A ; SIGNAL SUCCESS + RET +;----------------------------------------------------------------------------- +; RTC READ +; +; 1. ISSUE SLAVE ADDRESS WITH START CONDITION AND WRITE STATUS +; 2. OUTPUT THE ADDRESS TO ACCESS. (00H = START OF DS1307 REGISTERS) +; 3. OUTPUT REPEAT START TO TRANSITION TO READ PROCESS +; 4. ISSUE SLAVE ADDRESS WITH READ STATUS +; 5. DO A DUMMY READ +; 6. READ 8 BYTES STARTING AT ADDRESS PREVIOUSLY SET +; 7. END READ WITH NON-ACKNOWLEDGE +; 8. ISSUE STOP AND RELEASE BUS +; +DS7_RDC:LD A,DS7_WRITE ; SET SLAVE ADDRESS + OUT (PCF_RS0),A +; + CALL PCF_WAIT_FOR_BB + JP NZ,PCF_BBERR +; + CALL PCF_START ; GENERATE START CONDITION + CALL PCF_WAIT_FOR_PIN; AND ISSUE THE SLAVE ADDRESS + CALL NZ,PCF_PINERR +; + LD A,0 + OUT (PCF_RS0),A ; PUT ADDRESS MSB ON BUS + CALL PCF_WAIT_FOR_PIN + CALL NZ,PCF_PINERR +; + CALL PCF_REPSTART ; REPEAT START +; + LD A,DS7_READ ; ISSUE CONTROL BYTE + READ + OUT (PCF_RS0),A +; + CALL PCF_READI2C ; DUMMY READ +; + LD HL,DS7_BUF ; READ 8 BYTES INTO BUFFER + LD B,8 +DS7_RL1:CALL PCF_READI2C + LD (HL),A + INC HL + DJNZ DS7_RL1 +; +#IF (0) + LD A,8 + LD DE,DS7_BUF ; DISLAY DATA READ + CALL PRTHEXBUF ; + CALL NEWLINE +#ENDIF +; + LD A,PCF_ES0 ; END WITH NOT-ACKNOWLEDGE + OUT (PCF_RS1),A ; AND RELEASE BUS + NOP + IN A,(PCF_RS0) + NOP +DS7_WTPIN: + IN A,(PCF_RS1) ; READ S1 REGISTER + BIT 7,A ; CHECK PIN STATUS + JP NZ,DS7_WTPIN + CALL PCF_STOP +; + IN A,(PCF_RS0) + RET +; +;----------------------------------------------------------------------------- +; SET CLOCK +; +; IF THE CLOCK IS HALTED AS IDENTIFIED BY BIT 7 REGISTER 0, THEN ASSUME THE +; CLOCK HAS NOT BEEN SET AND SO SET THE CLOCK UP WITH A DEFAULT SET OF +; VALUES AS DEFINED IN THE DS7_CLKDATA TABLE. +; +DS7_SETC: + CALL PCF_WAIT_FOR_BB + JP NZ,PCF_BBERR +; + LD A,DS7_WRITE ; SET SLAVE ADDRESS + OUT (PCF_RS0),A +; + CALL PCF_START ; GENERATE START CONDITION + CALL PCF_WAIT_FOR_PIN; AND ISSUE THE SLAVE ADDRESS + CALL NZ,PCF_PINERR +; + LD A,00H ; REGISTER 00 + OUT (PCF_RS0),A ; PUT ADDRESS ON BUS + CALL PCF_WAIT_FOR_PIN + CALL NZ,PCF_PINERR +; + LD DE,DS7_CLKDATA +DS7_SC: LD A,(DE) + CP 0FFH + JR Z,DS7_ESC + OUT (PCF_RS0),A ; PUT DATA ON BUS + CALL PCF_WAIT_FOR_ACK + CALL NZ,PCF_ACKERR + INC DE + JR DS7_SC +; +DS7_ESC:CALL PCF_STOP + RET +; +DS7_CLKDATA: + .DB 00H ; SECONDS + .DB 00H ; MINUTES + .DB 00H ; HOURS + .DB 01H ; DAY + .DB 01H ; DATE + .DB 01H ; MONTH + .DB 21H ; YEAR + .DB DS7_CTL ; CONTROL (00010011B) + .DB 0FFH ; END FLAG +; +;----------------------------------------------------------------------------- +; DISPLAY CLOCK INFORMATION FROM DATA STORED IN BUFFER +; +DS7_DISP: + LD HL,DS7_CLKTBL +DS7_CLP:LD C,(HL) + INC HL + LD D,(HL) + CALL DS7_BCD + INC HL + LD A,(HL) + OR A + RET Z + CALL COUT + INC HL + JR DS7_CLP + RET +; +DS7_CLKTBL: + .DB 04H, 00111111B, '/' + .DB 05H, 00011111B, '/' + .DB 06H, 11111111B, ' ' + .DB 02H, 00011111B, ':' + .DB 01H, 01111111B, ':' + .DB 00H, 01111111B, 00H +; +DS7_BCD:PUSH HL + LD HL,DS7_BUF ; READ VALUE FROM + LD B,0 ; BUFFER, INDEXED BY A + ADD HL,BC + LD A,(HL) + AND D ; MASK OFF UNNEEDED + SRL A + SRL A + SRL A + SRL A + ADD A,30H + CALL COUT + LD A,(HL) + AND 00001111B + ADD A,30H + CALL COUT + POP HL + RET +; +DS7_BUF: .FILL 8,0 ; BUFFER FOR TIME, DATE AND CONTROL +;DS7_COLD .DB $80,$00,$00,$01,$01,$01,$00 ; COLD START RTC SETTINGS +; diff --git a/Source/HBIOS/pcf8584.asm b/Source/HBIOS/pcf8584.asm new file mode 100644 index 00000000..e53a4adb --- /dev/null +++ b/Source/HBIOS/pcf8584.asm @@ -0,0 +1,482 @@ +;================================================================================================== +; PCF8584 I2C CLOCK DRIVER +;================================================================================================== +; +PCF_BASE .EQU 0F0H +PCF_ID .EQU 0AAH +CPU_CLK .EQU 12 + +PCF_RS0 .EQU PCF_BASE +PCF_RS1 .EQU PCF_RS0+1 +PCF_OWN .EQU (PCF_ID >> 1) ; PCF'S ADDRESS IN SLAVE MODE +; +;T4LC512D .EQU 10100000B ; DEVICE IDENTIFIER +;T4LC512A1 .EQU 00000000B ; DEVICE ADDRESS +;T4LC512A2 .EQU 00001110B ; DEVICE ADDRESS +;T4LC512A3 .EQU 00000010B ; DEVICE ADDRESS +;T4LC512W .EQU 00000000B ; DEVICE WRITE +;T4LC512R .EQU 00000001B ; DEVICE READ +; +;I2CDEV1W .EQU (T4LC512D+T4LC512A1+T4LC512W) +;I2CDEV1R .EQU (T4LC512D+T4LC512A1+T4LC512R) +; +;I2CDEV2W .EQU (T4LC512D+T4LC512A2+T4LC512W) +;I2CDEV2R .EQU (T4LC512D+T4LC512A2+T4LC512R) +; +;I2CDEV3W .EQU (T4LC512D+T4LC512A3+T4LC512W) +;I2CDEV3R .EQU (T4LC512D+T4LC512A3+T4LC512R) +; +; CONTROL REGISTER BITS +; +PCF_PIN .EQU 10000000B +PCF_ES0 .EQU 01000000B +PCF_ES1 .EQU 00100000B +PCF_ES2 .EQU 00010000B +PCF_EN1 .EQU 00001000B +PCF_STA .EQU 00000100B +PCF_STO .EQU 00000010B +PCF_ACK .EQU 00000001B +; +PCF_START_ .EQU (PCF_PIN | PCF_ES0 | PCF_STA | PCF_ACK) +PCF_STOP_ .EQU (PCF_PIN | PCF_ES0 | PCF_STO | PCF_ACK) +PCF_REPSTART_ .EQU ( PCF_ES0 | PCF_STA | PCF_ACK) +PCF_IDLE_ .EQU (PCF_PIN | PCF_ES0 | PCF_ACK) +; +; STATUS REGISTER BITS +; +;PCF_PIN .EQU 10000000B +PCF_INI .EQU 01000000B ; 1 if not initialized +PCF_STS .EQU 00100000B +PCF_BER .EQU 00010000B +PCF_AD0 .EQU 00001000B +PCF_LRB .EQU 00001000B +PCF_AAS .EQU 00000100B +PCF_LAB .EQU 00000010B +PCF_BB .EQU 00000001B +; +; CLOCK CHIP FREQUENCIES +; +PCF_CLK3 .EQU 000H +PCF_CLK443 .EQU 010H +PCF_CLK6 .EQU 014H +PCF_CLK8 .EQU 018H +PCF_CLK12 .EQU 01cH +; +; TRANSMISSION FREQUENCIES +; +PCF_TRNS90 .EQU 000H ; 90 kHz */ +PCF_TRNS45 .EQU 001H ; 45 kHz */ +PCF_TRNS11 .EQU 002H ; 11 kHz */ +PCF_TRNS15 .EQU 003H ; 1.5 kHz */ +; +; TIMEOUT AND DELAY VALUES (ARBITRARY) +; +PCF_PINTO .EQU 65000 +PCF_ACKTO .EQU 65000 +PCF_BBTO .EQU 65000 +PCF_LABDLY .EQU 65000 +; +; DATA PORT REGISTERS +; +#IF (CPU_CLK = 443) +PCF_CLK .EQU PCF_CLK443 +#ELSE + #IF (CPU_CLK = 8) +PCF_CLK .EQU PCF_CLK8 + #ELSE + #IF (CPU_CLK = 12) +PCF_CLK .EQU PCF_CLK12 + #ELSE ***ERROR + #ENDIF + #ENDIF +#ENDIF +; +PCF8584_INIT: + CALL NEWLINE ; Formatting + PRTS("I2C: IO=0x$") + LD A, PCF_BASE + CALL PRTHEXBYTE + CALL PCF_INIT + CALL NEWLINE + RET +; +; LINUX DRIVER BASED CODE +; +; I2C_INB = IN A,(PCF_RS0) +; I2C_OUTB = LD A,* | OUT (PCF_RS0),A +; SET_PCF = LD A,* | OUT (PCF_RS1),A +; GET_PCF = IN A,(PCF_RS1) +; +;----------------------------------------------------------------------------- +PCF_START: + LD A,PCF_START_ + OUT (PCF_RS1),A + RET +; +;----------------------------------------------------------------------------- +PCF_REPSTART: + LD A,PCF_REPSTART_ + OUT (PCF_RS1),A + RET +; +;----------------------------------------------------------------------------- +PCF_STOP: + LD A,PCF_STOP_ + OUT (PCF_RS1),A + RET +; +;----------------------------------------------------------------------------- +; +PCF_INIT: + LD A,PCF_PIN ; S1=80H: S0 SELECTED, SERIAL + OUT (PCF_RS1),A ; INTERFACE OFF + NOP + IN A,(PCF_RS1) ; CHECK TO SEE S1 NOW USED AS R/W + AND 07FH ; CTRL. PCF8584 DOES THAT WHEN ESO + JP NZ,PCF_INIERR ; IS ZERO +; + LD A,PCF_OWN ; LOAD OWN ADDRESS IN S0, + OUT (PCF_RS0),A ; EFFECTIVE ADDRESS IS (OWN <<1) + NOP + IN A,(PCF_RS0) ; CHECK IT IS REALLY WRITTEN + CP PCF_OWN + JP NZ,PCF_SETERR +; + LD A,+(PCF_PIN | PCF_ES1) ; S1=0A0H + OUT (PCF_RS1),A ; NEXT BYTE IN S2 + NOP + IN A,(PCF_RS1) + AND 07FH + CP PCF_ES1 + JP NZ,PCF_REGERR +; + LD A,PCF_CLK ; LOAD CLOCK REGISTER S2 + OUT (PCF_RS0),A + NOP + IN A,(PCF_RS0) ; CHECK IT'S REALLY WRITTEN, ONLY + AND 1FH ; THE LOWER 5 BITS MATTER + CP PCF_CLK + JP NZ,PCF_CLKERR +; + LD A,PCF_IDLE_ + OUT (PCF_RS1),A + NOP + IN A,(PCF_RS1) + CP +(PCF_PIN | PCF_BB) + JP NZ,PCF_IDLERR +; + RET +; +;----------------------------------------------------------------------------- +PCF_HANDLE_LAB: +; + LD A,PCF_PIN + OUT (PCF_RS1),A + LD A,PCF_ES0 + OUT (PCF_RS1),A +; + LD HL,PCF_LABDLY +PCF_LABLP: + LD A,H + OR L + DEC HL + JR NZ,PCF_LABLP +; + IN A,(PCF_RS1) + RET +; +;----------------------------------------------------------------------------- +; +; RETURN A=00/Z IF SUCCESSFULL +; RETURN A=FF/NZ IF TIMEOUT +; RETURN A=01/NZ IF LOST ARBITRATION +; PCF_STATUS HOLDS LAST PCF STATUS +; +PCF_WAIT_FOR_PIN: + PUSH HL + LD HL,PCF_PINTO ; SET TIMEOUT VALUE + +PCF_WFP0: + IN A,(PCF_RS1) ; GET BUS + LD (PCF_STATUS),A ; STATUS + LD B,A + + DEC HL ; HAVE WE + LD A,H ; TIMED OUT + OR L + JR Z,PCF_WFP1 ; YES WE HAVE, GO ACTION IT + + LD A,B ; + AND PCF_PIN ; IS TRANSMISSION COMPLETE? + JR NZ,PCF_WFP0 ; KEEP ASKING IF NOT OR + POP HL ; YES COMPLETE (PIN=0) RETURN WITH ZERO + RET +PCF_WFP1: + LD A,B ; DID WE LOSE ARBITRATION? + AND PCF_LAB ; IF A=0 THEN NO + CPL + JR NZ,PCF_WFP2 ; NO + CALL PCF_HANDLE_LAB ; YES GO HANDLE IT + LD (PCF_STATUS),A + XOR A ; RETURN NZ, A=01H + INC A +PCF_WFP2: + POP HL ; RET NZ, A=FF IF TIMEOUT + RET +; +PCF_STATUS .DB 00H + +;-------------------------------------------------------------------------------- +; +; RETURN NZ/FF IF TIMEOUT ERROR +; RETURN NZ/01 IF FAILED TO RECEIVE ACKNOWLEDGE +; RETURN Z/00 IF RECEIVED ACKNOWLEDGE +; +PCF_WAIT_FOR_ACK: + PUSH HL + LD HL,PCF_ACKTO +; +PCF_WFA0: + IN A,(PCF_RS1) ; READ PIN + LD (PCF_STATUS),A ; STATUS + LD B,A +; + DEC HL ; SEE IF WE HAVE TIMED + LD A,H ; OUT WAITING FOR PIN + OR L ; EXIT IF + JR Z,PCF_WFA1 ; WE HAVE +; + LD A,B ; OTHERWISE KEEP LOOPING + AND PCF_PIN ; UNTIL WE GET PIN + JR NZ,PCF_WFA0 ; OR TIMEOUT +; + LD A,B ; WE GOT PIN SO NOW + AND PCF_LRB ; CHECK WE HAVE + LD A,1 + JR Z,PCF_WFA2 ; RECEIVED ACKNOWLEDGE + XOR A + JR PCF_WFA2 +PCF_WFA1: + CPL ; TIMOUT ERROR +PCF_WFA2: + POP HL ; EXIT WITH NZ = FF + RET +; +;-------------------------------------------------------------------------------- +; +; HL POINTS TO DATA +; DE = COUNT +; A = 0 LAST A=1 NOT LAST +; +; +;PCF_READBYTES: ; NOT FUNCTIONAL YET + + LD (PCF_LBF),A ; SAVE LAST BYTE FLAG +; + INC DE ; INCREMENT NUMBER OF BYTES TO READ BY ONE -- DUMMY READ BYTE + LD BC,0 ; SET BYTE COUNTER +; +PCF_RBL:PUSH BC + CALL PCF_WAIT_FOR_PIN ; DO WE HAVE THE BUS? + POP BC + JR Z,PCF_RB1 ; YES + CP 01H + JR Z,PCF_RB3 ; NO - LOST ARBITRATION + JR PCF_RB2 ; NO - TIMEOUT +; +PCF_RB1: + LD A,(PCF_STATUS) + AND PCF_LRB + + + ; IS THIS THE SECOND TO LAST BYTE TO GO? + + PUSH DE ; SAVE COUNT + DEC DE ; COUNT (DE) = NUMBER OF BYTES TO READ LESS 1 + EX DE,HL ; SAVE POINTER, PUT COUNT IN DE + XOR A ; CLEAR CARRY FLAG + SBC HL,BC ; DOES BYTE COUNTER = HL (NUMBER OF BYTES TO READ LESS 1) + EX DE,HL ; RESTORE POINTER + POP DE ; RESTORE COUNT + + ; Z = YES IT IS + ; NZ = NO IT ISN'T + JR NZ,PCF_RB4 +; +PCF_RB4:LD A,B ; IF FIRST READ DO A DUMMY + OR C ; READ OTHERWISE READ AND SAVE + JR NZ,PCF_RB5 + + IN A,(PCF_RS0) ; DUMMY READ + JR PCF_RB6 + +PCF_RB5:IN A,(PCF_RS0) ; READ AND SAVE + LD (HL),A +; +PCF_RB6: ; HAVE WE DONE ALL? + + PUSH DE ; SAVE COUNT + EX DE,HL ; SAVE POINTER, PUT COUNT IN DE + XOR A ; CLEAR CARRY FLAG + SBC HL,BC ; DOES BYTE COUNTER = HL (NUMBER OF BYTES TO READ) + EX DE,HL ; RESTORE POINTER + POP DE ; RESTORE COUNT +; + INC HL ; BUFFER POINTER + INC BC ; COUNT +; + JR NZ,PCF_RBL ; REPEAT UNTIL COUNTS MATCH + RET +; +PCF_RB2: ; TIMEOUT + CALL PCF_STOP + CALL PCF_TOERR + RET +; +PCF_RB3: ; LOST ARBITRATION + CALL PCF_ARBERR + RET +; +PCF_LBF: + .DB 0 ; LAST BYTE FLAG +; +;----------------------------------------------------------------------------- +; READ ONE BYTE FROM I2C +; RETURNS DATA IN A +; Z FLAG SET IS ACKNOWLEDGE RECEIVED (CORRECT OPERATION) +; +PCF_READI2C: + IN A,(PCF_RS1) ; READ S1 REGISTER + BIT 7,A ; CHECK PIN STATUS + JP NZ,PCF_READI2C + BIT 3,A ; CHECK LRB=0 + JP NZ,PCF_RDERR + IN A,(PCF_RS0) ; GET DATA + RET +;----------------------------------------------------------------------------- +; +; POLL THE BUS BUSY BIT TO DETERMINE IF BUS IS FREE. +; RETURN WITH A=00H/Z STATUS IF BUS IS FREE +; RETURN WITH A=FFH/NZ STATUS IF BUS +; +; AFTER RESET THE BUS BUSY BIT WILL BE SET TO 1 I.E. NOT BUSY +; +PCF_WAIT_FOR_BB: + LD HL,PCF_BBTO +PCF_WFBB0: + IN A,(PCF_RS1) + AND PCF_BB + RET Z ; BUS IS FREE RETURN ZERO + DEC HL + LD A,H + OR L + JR NZ,PCF_WFBB0 ; REPEAT IF NOT TIMED OUT + CPL ; RET NZ IF TIMEOUT + RET +; +;----------------------------------------------------------------------------- +; DISPLAY ERROR MESSAGES +; +PCF_RDERR: + PUSH HL + LD HL,PCF_RDFAIL + JR PCF_PRTERR +; +PCF_INIERR: + PUSH HL + LD HL,PCF_NOPCF + JR PCF_PRTERR +; +PCF_SETERR: + PUSH HL + LD HL,PCF_WRTFAIL + JR PCF_PRTERR +; +PCF_REGERR: + PUSH HL + LD HL,PCF_REGFAIL + JR PCF_PRTERR +; +PCF_CLKERR: + PUSH HL + LD HL,PCF_CLKFAIL + JR PCF_PRTERR +; +PCF_IDLERR: + PUSH HL + LD HL,PCF_IDLFAIL + JR PCF_PRTERR +; +PCF_ACKERR: + PUSH HL + LD HL,PCF_ACKFAIL + JR PCF_PRTERR +; +PCF_RDBERR: + PUSH HL + LD HL,PCF_RDBFAIL + JR PCF_PRTERR +; +PCF_TOERR: + PUSH HL + LD HL,PCF_TOFAIL + JR PCF_PRTERR +; +PCF_ARBERR: + PUSH HL + LD HL,PCF_ARBFAIL + JR PCF_PRTERR +; +PCF_PINERR: + PUSH HL + LD HL,PCF_PINFAIL + JR PCF_PRTERR +; +PCF_BBERR: + PUSH HL + LD HL,PCF_BBFAIL + JR PCF_PRTERR +; +PCF_PRTERR: + CALL PRTSTR + CALL NEWLINE + POP HL + RET +; +;----------------------------------------------------------------------------- +; DEBUG HELPER +; +#IF (0) +DS7_DBG: + PUSH AF + PUSH DE + PUSH HL + LD A,'[' + CALL COUT + LD HL,DS7_DBGF + LD A,(HL) + ADD A,'0' + INC (HL) + CALL COUT + LD A,']' + CALL COUT + POP HL + POP DE + POP AF + RET +DS7_DBGF: + .DB 0 ; DEBUG STAGE COUNTER +#ENDIF +; +PCF_NOPCF .DB "NO DEVICE FOUND$" +PCF_WRTFAIL .DB "SETTING DEVICE ID FAILED$" +PCF_REGFAIL .DB "CLOCK REGISTER SELECT ERROR$" +PCF_CLKFAIL .DB "CLOCK SET FAIL$" +PCF_IDLFAIL .DB "BUS IDLE FAILED$" +PCF_ACKFAIL .DB "FAILED TO RECEIVE ACKNOWLEDGE$" +PCF_RDFAIL .DB "READ FAILED$" +PCF_RDBFAIL .DB "READBYTES FAILED$" +PCF_TOFAIL .DB "TIMEOUT ERROR$" +PCF_ARBFAIL .DB "LOST ARBITRATION$" +PCF_PINFAIL .DB "PIN FAIL$" +PCF_BBFAIL .DB "BUS BUSY$"