 The Museum of HP Calculators

HP Articles Forum

Internet Protocol (v4) Addresses on the HP-16C

Posted by Cameron Paine on 20 Dec 2005, 2:36 a.m.

An IPv4 address is simply a 32-bit unsigned integer. An address is given a sub-structure by conventional rules that divide the address pool into three classes based on numerical range. The sub-structure can be further refined by applying a 32-bit mask to the address.

Conventionally, addresses and masks are written using dotted-decimal notation. In this system, each of the four octets that make up the address (or the mask) are expressed in decimal, with a dot separating each octet. The left-hand position holds the most-significant octet.

For example:

192.168.192.42 255.255.192.0

There is an alternative notation for network masks in which a single integer, representing the number of bits that are set in the mask, is appended to a dotted-decimal address, preceded by a slash character. This is sometimes called CIDR notation. Using this scheme, the above address/mask combination would be expressed as:

192.168.192.42/18

This is a useful notation because the actual mask can be conveniently generated using the number after the slash and the 16C's left mask (MASKL) operator.

## The Package

The routines in this package manipulate IPv4 addresses and network masks in various useful ways. None of the functions provided are particularly ingenious but collectively they can save quite a few keystrokes.

User Routines

```GSB A - JOIN dotted decimal octets to 32-bit integer
GSB B - SPLIT 32-bit integer to dotted decimal octets
GSB C - NETwork address from CIDR
GSB D - BCAST (broadcast) address from CIDR
GSB E - Numnber of host ADDResses given a mask
```

Service Routines

```GSB 9 - convert MASK in register 0 to CIDR form.
GSB 8 - OCTET processor for SPLIT
GSB 7 - convert mask in X to CIDR MASK in X
```

Input and Output

The 16C has no native dotted-decimal representation. Therefore we use the four stack registers as follows:

```T := octet 3 (ms)
Z := octet 2
Y := octet 1
X := octet 0 (ls)
```

For those functions that require CIDR addresses, the mask should be stored in Register 0. If the mask is in binary form it will be converted to CIDR form as required. Thus 192.168.192.42/26 is entered as:

```26 STO 0
192 ENTER
168 ENTER
192 ENTER
42
```

The four octets in a returned address can be retrieved by using the roll-down key.

All routines use I for temporary storage. They may be trivially modified to use another register for that purpose. The calculator must be in unsigned decimal mode with a 32-bit word size.

```; JOIN - dotted decimal octets to 32-bit integer
+01 - LBL JOIN (A)
+02 - R^
+03 - STO I	; I = o3
+04 - Rv
+05 - X-Y	; x = o1; y = o0
+06 - 	; discards T
+07 - RLn	; x = o1 << 8
+08 - LSTx	; bring back 8...
+09 - Rv	; ...and put it in T
+10 - OR	; x = o0 | o1 << 8; y = o2; z = 8; t = 8
+11 - X-Y	; x = o2
+12 - R^	; bring back 8...
+13 - SL	; ...make it 16
+14 - RLn	; x = o2 << 16
+15 - LSTx	; bring back 16...
+16 - R^	; bring back 8...
+17 - OR	; ...make it 24
+18 - Rv	; x = o2 << 16; y = o0 | o1 << 8; t = 24
+19 - OR	; x = o2 << 16 | o0 | o1 << 8
+20 - RCL I	; x = o3
+21 - R^	; x = 24
+22 - RLn	; x = o3 << 24
+23 - OR	; x = o3 << 24 | o2 << 16 | o0 | o1 << 8
+24 - RTN
; SPLIT - 32-bit integer to dotted decimal octets
+25 - LBL SPLIT (B)
+26 - GSB OCTET	; do o0
+27 - Rv
+28 - STO I	; stash in I
+29 - R^
+30 - GSB OCTET	; do o1
+31 - Rv
+32 - X-I	; stash o1, stack o0
+33 - R^
+34 - GSB OCTET	; do o2 and o3
+35 - X-Y	; x = o2; y = o3
+36 - R^
+37 - X-I	; x = o1; y = o2; z = o3
+38 - R^	; x = o0; y = o1; z = o2; t = o3
+39 - RTN
; NET - network address from CIDR host address
+40 - LBL NET (C)
+41 - GSB JOIN
+42 - GSB MASK
+43 - MASKL
+44 - AND
+45 - GTO SPLIT
; BCAST - broadcast address from CIDR network address
+46 - LBL BCAST (D)
+47 - GSB JOIN
+48 - GSB MASK
+49 - MASKL
+50 - NOT
+51 - OR
+52 - GTO SPLIT
; NADDR - number of host addresses on a network
+53 - LBL NADDR (E)
+54 - X=0?
+55 - RCL 0
+56 - X=0?
+57 - RTN
+58 - GSB CIDR_MASK (7)
+59 - MASKL
+60 - NOT
+61 - 
+62 - [-]
+63 - RTN
;
; Service Routines
;
; If the high bit of X is set we assume it contains a binary
; mask and we convert it to CIDR form. Otherwise we leave it
; alone.
+64 - LBL CIDR_MASK (7)
+65 - 
+66 - 
+67 - B?
+68 - B#
+69 - RTN
; Places the low-order octet of X in Y and the remaining
; high-order bits, right justified, in X.
+70 - LBL OCTET (8)
+71 - 
+72 - MASKR	; low octet mask
+73 - X-Y	; swap so we stash in LSTx
+74 - AND	; clear high bits
+75 - LSTx	; X = word; Y = octet;
+76 - 	; Clear low octet so we can rotate
+77 - MASKR	; low octet mask...
+78 - NOT	; ...becomes remaining octet mask
+79 - AND	; clear low octet
+80 - 
+81 - RRn	; rotate cleared octet to MSB
+82 - RTN
+83 - LBL MASK (9)
+84 - RCL 0
+85 - GTO CIDR_MASK (7)
```

When entered into an otherwise empty 16C, with the word size set to 32 bits, [f][MEM] should show:

```P - 6  r - 028
```

If you don't have a 16C handy and you'd like to try these out you can download the package for Nonpareil here or for my simulator here.

Edited: 20 Dec 2005, 2:40 a.m.

 Password: