Home‎ > ‎Michael's Projects‎ > ‎

Useful 8085 Subroutines

I wrote these subroutines while learning how to program on the MiniMax8085 board -- a simple 8085-based single board computer (SBC). My board's RAM starts at 0x8000, so that's where the subroutines are. You should update the addresses and jump instructions based on your RAM size (E.G. if it has 8K of RAM, start at 0xE000). To load the subroutines on MON85, use i ADDR (ADDR is the address of the start) and then paste in the Intel hex (listed after the assembly).


Display character ( 0x8200 - 0x820B )

Arguments

  • Input:
    • C - Character to print
  • Output:
    • Character printed to the USART

Assembly

8200    DB 09        IN   09
8202    E6 01        ANI  01
8204    CA 00 82     JZ   8200
8207    79           MOV  A,C
8208    D3 08        OUT  08
820A    C9           RET

Intel HEX

:0C820000DB09E601CA008279D308C9003E
:00000001FF

Display text string at HL ( 0x8100 - 0x810F )

Arguments

  • Input:
    • HL - Address of the text string to print
  • Output:
    • String printed to the USART

Assembly

8100    3E 00       MVI  A 00
8102    4E          MOV  C,M
8103    B9          CMP  C
8104    CA 0E 81    JZ   810E
8107    23          INX  H
8108    CD 00 82    CALL 8200
810B    C3 00 81    JMP  8100
810E    C9          RET

Intel HEX

:108100003E004EB9CA0E8123CD0082C30081C90052
:00000001FF

Read character from USART ( 0x8180 - 0x818A )

Arguments

  • Input:
    • none
  • Output:
    • A - Character from the USART

Assembly

8180    D8 09       IN  09
8182    E6 02       ANI 02
8184    CA 80 81    JS  8180
8187    D8 08       IN  08
8189    C9          RET

Intel HEX

:108100003E004EB9CA0E8123CD0082C30081C90052
:00000001FF

Print HEX byte in ASCII ( 0x8280 - 0x82A0 )

Arguments

  • Input:
    • C - Byte to print
  • Output:
    • Byte printed to the USART

Assembly

8280    F5           PUSH PSW    ; Push acc. and flags
8281    79           MOV  A,C    ; Copy input into acc.
8282    E6 0F        ANI  0F     ; Get lower half of acc.
8284    C6 30        ADI  30     ; Add 0x30 (ascii '0') to acc.
8286    FE 39        CPI  3A     ; See if acc. is greater than 9 (characters after digits are ":;<=>?")
8288    DA 8D 82     JC   828E   ; Acc. is not a hex number, so skip adding
828B    C6 07        ADI  07     ; Add 0x07 to get to capital letters (use 0x27 if you want lower case)
828D    47           MOV  B,A    ; Move character into B to be later moved into C for printing
828E    79           MOV  A,C    ; See 8281
828F    E6 F0        ANI  F0     ; See 8282
8291    07           RLC         ; Shift
8292    07           RLC         ; Acc.
8293    07           RLC         ; Four
8294    07           RLC         ; Bits
8295    C6 30        ADI  30     ; See 8284
8297    FE 39        CPI  3A     ; See 8286
8299    DA 9E 82     JC   829F   ; See 8288
829C    C6 07        ADI  07     ; See 828B
829E    4F           MOV  C,A    ; Move character into C to be printed first
829F    F1           POP  PSW    ; Pop acc. and flags
82A0    C9           RET         ; Exit

Explanation

Lets use an example: 0x7F (01111111)

  1. Get the lower 4-bits (nibble) of the input: 0x0F
  2. Add 0x30 - the ASCII code of "0": 0x3F
  3. If the result value is greater than 0x39:
    • Add 0x07, so that the values from 0xA to 0xF are translated to the ASCII codes of "A" to "F": 0x46
  4. Store the result value (ASCII code) into B
  5. Get the higher 4-bits (nibble) of the input: 0x70
  6. Shift the value left 4 times: 0x07
  7. Add 0x30 - the ASCI code of "0": 0x37
  8. If the result is value greater than 0x39:
    • No
  9. Store the result value (ASCII code) into C
  10. Return

Intel HEX

:10828000F579E60FC630FE3ADA8D82C6074779E601
:10829000F007070707C630FE3ADA9E82C6074FF19D
:0182A000C914
:00000001FF

Multiply two 8-bit numbers ( 0x8300 - 0x8322)

Arguments

  • Input:
    • B,C - Factors
  • Output:
    • HL - product

Assembly

8300    F5         PUSH PSW
8301    C5         PUSH B
8302    D5         PUSH D
8303    26 00      MVI  H,$00
8305    6C         MOV  L,H
8306    54         MOV  D,H
8307    59         MOV  E,C
8308    78         MOV  A,B
8309    37         STC
830A    3F         CMC
830B    1F         RAR
830C    47         MOV  B,A
830D    D2 11 83   JNC  $8311
8310    19         DAD  D
8311    37         STC
8312    3F         CMC
8313    7B         MOV  A,E
8314    17         RAL
8315    5F         MOV  E,A
8316    7A         MOV  A,D
8317    17         RAL
8318    57         MOV  D,A
8319    3E 00      MVI  A,$00
831B    B8         CMP  B
831C    C2 08 83   JNZ  $8308
831F    D1         POP  D
8320    C1         POP  B
8321    F1         POP  PSW
8322    C9         RET

Explanation

Lets use the example of B: 0x06 (00000110) times C: 0x0B (00001011)

Start with a standard multiplication layout but in binary:
  00001011
x 00000110
----------

Expand the top value (stored in register C) to a 16 bit value (stored in register pair DE), and zero the output value (register pair HL):
  0000000000001011
x         00000110
------------------
  0000000000000000

In a loop:

Shift the bottom value (register B) to the right through carry:
  0000000000001011
x         00000011 Carry = 0
------------------
  0000000000000000

If the carry flag is set, add the top value (register pair DE) to the output (register pair HL) and reset the carry flag

Shift the top value (register pair DE) to the left;
  0000000000010110
x         00000011 Carry = 0
------------------
  0000000000000000

If the bottom value is not zero, repeat the loop:
  0000000000010110
x         00000001 Carry = 1
------------------
  0000000000010110

  0000000000101100
x         00000001 Carry = 0
------------------
  0000000000010110

  0000000000101100
x         00000000 Carry = 1
------------------
  0000000000010110

  0000000001011000
x         00000000 Carry = 0
------------------
           1111
  0000000000101100
+ 0000000000010110
------------------
  0000000001000010
Now that the bottom value is zero, the loop stops and subroutine returns the value of 0x42 (0000000001000010) in register pair HL

Now lets see how the subroutine works with the factors C = 0x1B (00011011) x B = 0x97 (10010111)

  0000000000011011
x         10010111
------------------
  0000000000000000

  0000000000011011
x         01001011 Carry = 1
------------------
  0000000000000000

  0000000000110110
x         01001011 Carry = 0
------------------
  0000000000011011

  0000000000110110
x         00100101 Carry = 1
------------------
  0000000000011011

  0000000001101100
x         00100101 Carry = 0
------------------
           11111
  0000000000110110
+ 0000000000011011
------------------
  0000000001010001

  0000000001101100
x         00010010 Carry = 1
------------------
  0000000001010001

  0000000011011000
x         00010010 Carry = 0
------------------
          1
  0000000001101100
+ 0000000001010001
------------------
  0000000010111101

  0000000011011000
x          0001001 Carry = 0
------------------
  0000000010111101

  0000000110110000
x          0001001 Carry = 0
------------------
  0000000010111101

  0000000110110000
x          0000100 Carry = 1
------------------
  0000000010111101

  0000001101100000
x         00000100 Carry = 0
------------------
        11 11
  0000000110110000
+ 0000000010111101
------------------
  0000001001101101

  0000001101100000
x         00000010 Carry = 0
------------------
  0000001001101101

  0000011011000000
x         00000010 Carry = 0
------------------
  0000001001101101

  0000011011000000
x         00000001 Carry = 0
------------------
  0000001001101101

  0000110110000000
x         00000001 Carry = 0
------------------
  0000001001101101

  0000110110000000
x         00000000 Carry = 1
------------------
  0000001001101101

  0001101100000000
x         00000000 Carry = 0
------------------
  0000110110000000
+ 0000001001101101
------------------
  0000111111101101

The subroutine exits with an answer of 0x0FED (0000111111101101) in register pair HL

Intel HEX

:10830000F5C5D526006C545978373F1F47D2118329
:1083100019373F7B175F7A17573E00B8C20883D125
:03832000C1F1C981
:00000001FF

Comments