; ; Substract two 16-bit BCD numbers using SUB/CBC instructions with BCD correction using DAA instruction ; .ORG 100H ; CP/M programs start address JR START ; Go to program start ; ; Variable storage space ; OPER1 .DW 6912H ; 6912D (packed BCD) OPER2 .DW 5678H ; 5678D (packed BCD) RESULT .DW 0000H Stack1 .DW 0 ; Place to save old stack Sbot .DS 64 ; Temp stack for us to use ; ; Constants ; STOP .EQU $-1 ; Top of our stack BDOS .EQU 5 ; Address of BDOS entry ; ; Peripheral I/O addresses ; LEDS .EQU 00H ; Digital I/O board PIO1_A_D .EQU 068H ; Z80 PIO #1 PIO1_A_C .EQU 06AH PIO1_B_D .EQU 069H PIO1_B_C .EQU 06BH PIO2_A_D .EQU 06CH ; Z80 PIO #2 PIO2_A_C .EQU 06EH PIO2_B_D .EQU 06DH PIO2_B_C .EQU 06FH PIO3_A_D .EQU 0F0H ; Z80 PIO #3 PIO3_A_C .EQU 0F2H PIO3_B_D .EQU 0F1H PIO3_B_C .EQU 0F3H PIO4_A_D .EQU 0F4H ; Z80 PIO #4 PIO4_A_C .EQU 0F6H PIO4_B_D .EQU 0F5H PIO4_B_C .EQU 0F7H ; ; Start of code segment ; START: LD HL, 0000H ; HL = 0 ADD HL, SP ; HL = SP LD (Stack1), HL ; Save original stack LD HL, STOP ; HL = address of new stack LD SP, HL ; Stack pointer = our stack ; ------------------------------------------------------------ ; Initialize Z80 PIO's LD A, 0FH ; Control word for PIO, set output mode OUT (PIO1_A_C), A ; PIO #1 port A OUT (PIO1_B_C), A ; PIO #1 port B OUT (PIO2_A_C), A ; PIO #2 port A OUT (PIO2_B_C), A ; PIO #2 port B OUT (PIO3_A_C), A ; PIO #2 port A OUT (PIO3_B_C), A ; PIO #2 port B OUT (PIO3_A_C), A ; PIO #3 port A OUT (PIO3_B_C), A ; PIO #3 port B OUT (PIO4_A_C), A ; PIO #4 port A OUT (PIO4_B_C), A ; PIO #4 port B ; Turn all LED's OFF XOR A ; LD A, 0 -> XOR A OUT (LEDS), A OUT (PIO1_A_D), A OUT (PIO1_B_D), A OUT (PIO2_A_D), A OUT (PIO2_B_D), A OUT (PIO3_A_D), A OUT (PIO3_B_D), A OUT (PIO4_A_D), A OUT (PIO4_B_D), A CALL DELAY ; Print operand 1 LD A, (OPER1 + 1) ; Load (OPER1) HIGH into A OUT (PIO1_B_D), A ; Set LEDs in PIO #1 ch. B with 1st operand HIGH CALL PRINT_BCD CALL DELAY LD A, (OPER1) ; Load (OPER1) LOW into A OUT (PIO1_A_D), A ; Set LEDs in PIO #1 ch. A with 1st operand CALL PRINT_BCD CALL DELAY LD E, '-' CALL BDOS2 CALL DELAY ; Print operand 2 LD A, (OPER2 + 1) ; Load (OPER2) HIGH into A OUT (PIO2_B_D), A ; Set LEDs in PIO #2 ch. B with 2nd operand HIGH CALL PRINT_BCD CALL DELAY LD A, (OPER2) ; Load (OPER2) LOW into A OUT (PIO2_A_D), A ; Set LEDs in PIO #2 ch. A with 2nd operand LOW CALL PRINT_BCD CALL DELAY ; ; Compute: RESULT = OPER1 - OPER2 ; LD A, (OPER1) ; Load (OPER1) LOW into A LD HL, OPER2 ; Load OPER2 address into HL SUB (HL) ; (OPER1 - OPER2) LOW: 12H-78H=9AH DAA ; Decimal Adjust: DAA adds 9AH: so result is 134H [CY=1 A=34] LD (RESULT), A ; Store (RESULT) LOW PUSH AF ; Store Flags to stack ... POP BC ; ... and restore it to C reg. LD A, C ; Flags is in A now OUT (LEDS), A ; Out Flags to Digital I/O - expect LED0: ON => bcs. Carry Flag = 1 LD A, (OPER1 + 1) ; LD (OPER1) HIGH into A INC HL ; Point to OPER2 + 1 SBC A, (HL) ; (OPER1 - OPER2) HIGH - Carry Flag: 69H-56H-1=12H DAA ; Decimal Adjust, does nothing at this case LD (RESULT + 1), A ; Store (RESULT) HIGH ; Print result LD E, '=' CALL BDOS2 LD A, (RESULT + 1) ; Load (RESULT) HIGH into A CALL PRINT_BCD CALL REVERSE ; Because PIO #3 has LED's in reverse order: 0-7 OUT (PIO3_A_D), A ; Set LEDs in PIO #3 ch. A with Result HIGH CALL DELAY LD A, (RESULT) ; Load (RESULT) LOW into A CALL PRINT_BCD CALL REVERSE ; Because PIO #3 has LED's in reverse order: 0-7 OUT (PIO3_B_D), A ; Set LEDs in PIO #3 ch. B with Result LOW CALL DELAY ; ------------------------------------------------------------ ; Finish and return to CP/M EXIT: LD HL, (Stack1) ; HL = entry stack address LD SP, HL ; SP = value on entry RET ; Return control back to CP/M ;-------------------------------------------------------------------------------------- ; ; Print BCD number in A ; PRINT_BCD: PUSH AF \ PUSH AF RRA \ RRA \ RRA \ RRA ; Rotate HIGH nibble right to LOW AND 00001111B ; Mask HIGH nibble ADD A, '0' ; Convert to ASCII LD E, A CALL BDOS2 POP AF ; Restore A back AND 00001111B ; Mask HIGH nibble ADD A, '0' ; Convert to ASCII LD E, A CALL BDOS2 POP AF ; Restore A again RET ;-------------------------------------------------------------------------------------- ; ; BDOS function 2 (C_WRITE) - Console output, char in E ; BDOS2: PUSH AF PUSH BC PUSH DE PUSH HL LD C, 2 ; We want BDOS func 2 CALL BDOS ; Entered with C = 2, E = ASCII character POP HL POP DE POP BC POP AF RET ;-------------------------------------------------------------------------------------- ; ; Reverse bits in A ; 8 bytes / 206 cycles ; REVERSE: LD B, 8 LD L, A REVLOOP: RL L RRA DJNZ REVLOOP RET ;-------------------------------------------------------------------------------------- ; DELAY: ; Routine to add a delay ; PUSH BC PUSH DE LD C, 10 DELAY0: LD D, 0FFH DELAY1: LD B, 0FFH DELAY2: NOP DJNZ DELAY2 DEC D JR NZ, DELAY1 DEC C JR NZ, DELAY0 POP DE POP BC RET ;-------------------------------------------------------------------------------------- ;-------------------------------------------------------------------------------------- .END