; ; DAA trick ; Normally DAA instruction is used for BCD math but can be used for converting (?) ASCII integer. ; https://wikiti.brandonw.net/index.php?title=Z80_Optimization ; .ORG 100H ; CP/M programs start address JP START ; Go to program start ; ; Variable storage space ; MSG .DB "Enter number 0 - 9:", 13, 10, 0 MSG_EOL .DB 13, 10, 0 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 adresses ; 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: ; ------------------------------------------------------------ ; Starting sequence for CP/M programs 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 #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 ; ------------------------------------------------------------ LOOP: ; DAA trick LD HL, MSG ; MSG HL = address of string CALL SEND_STR_CON ; Send string in (HL) to console LD A, 00000001B OUT (LEDS), A CALL DELAY LD A, 00000010B OUT (LEDS), A CALL BDOS1 ; Wait until the keyboard is ready to provide a character, and return it in A LD HL, MSG_EOL ; MSG_EOL HL = address of string PUSH AF CALL SEND_STR_CON ; Send string in (HL) to console POP AF SUB 030H ; ASCII to binary OUT (PIO1_A_D), A CALL DELAY CP 10 ; If A < N, then Carry Flag is set. If A >= N, then Carry Flag is reset CCF ; Inverts the C Flag ADC A, 030H ; 030H is ASCII '0'. The sum of the A and operand plus the Carry Flag (0 or 1) is calculated DAA ; Decimal adjust register A based upon last arithmetic logic unit operation LD C, A CALL PRINTC OUT (PIO1_B_D), A LD A, 00000100B OUT (LEDS), A ;IN A, (LEDS) ; Read buttons on I/O board ;OR 0 ; Set Zero Flag ;JR NZ, EXIT ; If any button pressed, exit ;JR LOOP ; ------------------------------------------------------------ ; LED's OFF EXIT: LD A, 0 OUT (LEDS), A ; Send A to Digital I/O board ; ------------------------------------------------------------ ; Finish and return to CP/M LD HL, (Stack1) ; HL = entry stack address LD SP, HL ; SP = value on entry RET ; Return control back to CP/M ;-------------------------------------------------------------------------------------- ; DELAY: ; Routine to add a delay ; PUSH BC PUSH DE LD C, 12 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 ;-------------------------------------------------------------------------------------- ;-------------------------------------------------------------------------------------- ; ; Routine to print C register as ASCII decimal ; PRINTC: PUSH AF PUSH BC PUSH DE LD A, C CALL DTOA3D ; Split A register into B, D and E ; Print first digit in B LD A, B CP '0' ; Don't bother printing leading '0' JR Z, PRINTC3 CALL BDOS2 ; Send char in A to console PRINTC3: ; Print second digit in D LD A, D ; Second digit will be tested for '0' CP '0' ; Don't bother printing leading '0' JR NZ, PRINT_DIGIT2 LD A, B ; First digit will be tested for '0' CP '0' ; Don't bother printing leading '0' JR Z, PRINTC2 LD A, D ; Put back second digit to A PRINT_DIGIT2: CALL BDOS2 ; Send char in A to console PRINTC2: LD A, E ; Print third digit in E CALL BDOS2 ; Send char in A to console LD HL, MSG_EOL ; MSG_EOL HL = address of string CALL SEND_STR_CON ; Send string in (HL) to console POP DE POP BC POP AF RET ;-------------------------------------------------------------------------------------- ; ; Binary to ASCII Decimal, in: A, out: BDE ; DTOA3D: LD B, '0' ; Starting from ASCII '0' DEC B ; Because we are inc'ing in the loop LD D, 100 ; Want base 100 please AND A ; Clear C Flag DTOA3DLOOP: INC B ; Increase the number of hundreads SUB D ; Take away one unit of hundread from A JR NC, DTOA3DLOOP ; If A still hasn't gone negative, do another ADD A, D ; Decreased it too much, put it back LD D, '0' ; Starting from ASCII '0' DEC D ; Because we are inc'ing in the loop LD E, 10 ; Want base 10 please AND A ; Clear C Flag DTOA2DLOOP: INC D ; Increase the number of tens SUB E ; Take away one unit of ten from A JR NC, DTOA2DLOOP ; If A still hasn't gone negative, do another ADD A, E ; Decreased it too much, put it back ADD A, '0' ; Convert to ASCII LD E, A ; Stick remainder in E RET ;-------------------------------------------------------------------------------------- ;-------------------------------------------------------------------------------------- ; ; Send zero-terminated string in (HL) to console ; SEND_STR_CON: LD A, (HL) ; Read string char OR A ; Set CPU flags RET Z ; If char = 0 done CALL BDOS2 ; Send char in A to console INC HL ; Point to next char JR SEND_STR_CON ; Do next char ;-------------------------------------------------------------------------------------- ; ; Wait for a character from the keyboard; then echo it to the screen and return it. ; Send the character in A to the console ; BDOS1: PUSH BC PUSH DE PUSH HL LD C, 1 ; BDOS function 1 (C_READ) - Console input CALL BDOS ; Call BDOS function - Entered with C=1, Returns A=L=character POP HL POP DE POP BC RET ;-------------------------------------------------------------------------------------- ; ; Send the character in A to the console ; BDOS2: PUSH BC PUSH DE PUSH HL LD E, A LD C, 2 ; BDOS function 2 (C_WRITE) - Console output CALL BDOS ; Call BDOS function - Entered with C=2, E=ASCII character POP HL POP DE POP BC RET ;-------------------------------------------------------------------------------------- ;-------------------------------------------------------------------------------------- .END