; KCPSM3 Program - Implementation of the SHA-1 algorithm for use with the ; DS2432 secure memory on the Spartan-3E Starter Kit. ; ; Ken Chapman - Xilinx Ltd ; ; Version v1.00 - 19th April 2006 ; ; ; IMPORTANT - This design builds on the reference design called "PicoBlaze ; DS2432 communicator". It is highly recommend that you look at that ; design before proceeding with this one. ; ; ; This program uses a 9600 baud UART connection to allow communication with the ; 1-wire interface of the DS2432 memory device from Dallas Semiconductor. ; ; The program only supports a limited number of the DS2432 commands to focus on ; those aspects which use the SHA-1 algorithm. ; ; Note that the code performing the SHA-1 algorithm interacts with the hardware of ; this complete reference design. The hardware provides a 16 word (32-bit) buffer ; combined used in the initialisation of the algorithm and subsequent computation ; of the Wt words. ; ; ; The DS2432 should be programmed with a 64-bit secret. The following constants ; define the secret which will be used. Obviously this would be be changed in a ; real application and further measures taken to prevent it easily being found. ; The secret is 64-bits formed of 8 bytes. 'secret0' would be stored at address ; 0080 of the DS2432 and 'secret7' at address 0087. The write buffer and load ; first secret commands allow you to set any secret into the DS2432 device but ; this program always uses the secret defined in these constants such that you can ; experiment with secrets which do and do not match. ; ; CONSTANT secret0, 01 CONSTANT secret1, 23 CONSTANT secret2, 45 CONSTANT secret3, 67 CONSTANT secret4, 89 CONSTANT secret5, AB CONSTANT secret6, CD CONSTANT secret7, EF ; ; ; Bytes 4, 5 and 6 of the DS2432 scratch pad memory are used in the SHA-1 algorithm. ; These should be set using the write scratchpad memory command before using the ; read authenticated page command. HOWEVER, it is also important that you also use ; the read scratchpad command BEFORE using the read authenticated page command. This ; is because this program only copies the bytes 4, 5 and 6 during a read such that ; they are can be used by the PicoBlaze SHA-1 algorithm. This limitation is deliberate ; so that you can experiment and prove that the SHA-1 results will not match if ; the same 'challenge' bytes are not used. ; ; ;************************************************************************************** ; Port definitions ;************************************************************************************** ; ; CONSTANT status_port, 40 ;UART status input CONSTANT tx_half_full, 01 ; Transmitter half full - bit0 CONSTANT tx_full, 02 ; FIFO full - bit1 CONSTANT rx_data_present, 04 ; Receiver data present - bit2 CONSTANT rx_half_full, 08 ; FIFO half full - bit3 CONSTANT rx_full, 10 ; full - bit4 CONSTANT spare1, 20 ; spare '0' - bit5 CONSTANT spare2, 40 ; spare '0' - bit6 CONSTANT spare3, 80 ; spare '0' - bit7 ; CONSTANT UART_read_port, 80 ;UART Rx data input ; CONSTANT UART_write_port, 04 ;UART Tx data output ; ; CONSTANT DS_wire_in_port, C0 ;Read signal from DS2432 device CONSTANT DS_wire_out_port, 08 ;Drive signal to DS2432 device (open collector) CONSTANT DS_wire, 01 ; Signal is bit0 in both cases ; ; ; ; The following ports access the 'Wt' word buffer. This buffer holds 16 words ; of 32-bits organised as a 64-byte shift register. Hence each word is stored ; by writing 4 bytes. As each byte is written, all bytes shift along such that ; older Wt values can be read from consistent port addresses. ; CONSTANT W_word_write_port, 10 ;Write byte to Wt buffer ; CONSTANT Wt_minus3_byte0_read_port, 08 ;Read of Wt-3 CONSTANT Wt_minus3_byte1_read_port, 09 CONSTANT Wt_minus3_byte2_read_port, 0A CONSTANT Wt_minus3_byte3_read_port, 0B ; CONSTANT Wt_minus8_byte0_read_port, 1C ;Read of Wt-8 CONSTANT Wt_minus8_byte1_read_port, 1D CONSTANT Wt_minus8_byte2_read_port, 1E CONSTANT Wt_minus8_byte3_read_port, 1F ; CONSTANT Wt_minus14_byte0_read_port, 34 ;Read of Wt-14 CONSTANT Wt_minus14_byte1_read_port, 35 CONSTANT Wt_minus14_byte2_read_port, 36 CONSTANT Wt_minus14_byte3_read_port, 37 ; CONSTANT Wt_minus16_byte0_read_port, 3C ;Read of Wt-16 CONSTANT Wt_minus16_byte1_read_port, 3D CONSTANT Wt_minus16_byte2_read_port, 3E CONSTANT Wt_minus16_byte3_read_port, 3F ; ; ;************************************************************************************** ; Special Register usage ;************************************************************************************** ; NAMEREG sF, UART_data ;used to pass data to and from the UART ; ; ;************************************************************************************** ; Scratch Pad Memory Locations ;************************************************************************************** ; ; Scratch pad memory provides 64 bytes in the address range 00 to 3F hex. ; ; ; Locations for device family code, serial number and 8-bit CRC value ; CONSTANT family_code, 00 CONSTANT serial_number0, 01 ;48-bit serial number LS-Byte first CONSTANT serial_number1, 02 CONSTANT serial_number2, 03 CONSTANT serial_number3, 04 CONSTANT serial_number4, 05 CONSTANT serial_number5, 06 CONSTANT read_ROM_CRC, 07 ;8-bit CRC ; ; ; Locations for variables used in SHA-1 algorithm. ; Each variable is 32-bits and requires 4 bytes to store. ; '0' indicates the least significant byte and '3' the most significant byte. ; ; Note that the concatenation of 'A', 'B', 'C', 'D' and 'E' will be the 160-bit MAC. ; CONSTANT var_A0, 08 ;Variable 'A' CONSTANT var_A1, 09 CONSTANT var_A2, 0A CONSTANT var_A3, 0B ; CONSTANT var_B0, 0C ;Variable 'B' CONSTANT var_B1, 0D CONSTANT var_B2, 0E CONSTANT var_B3, 0F ; CONSTANT var_C0, 10 ;Variable 'C' CONSTANT var_C1, 11 CONSTANT var_C2, 12 CONSTANT var_C3, 13 ; CONSTANT var_D0, 14 ;Variable 'D' CONSTANT var_D1, 15 CONSTANT var_D2, 16 CONSTANT var_D3, 17 ; CONSTANT var_E0, 18 ;Variable 'E' CONSTANT var_E1, 19 CONSTANT var_E2, 1A CONSTANT var_E3, 1B ; ; ; Copy of data in the scratchpad memory of the DS2432. ; This is only updated by the read scratchpad memory command. ; '0' indicates the data in the least significant location. ; CONSTANT scratchpad0, 1C CONSTANT scratchpad1, 1D CONSTANT scratchpad2, 1E CONSTANT scratchpad3, 1F CONSTANT scratchpad4, 20 CONSTANT scratchpad5, 21 CONSTANT scratchpad6, 22 CONSTANT scratchpad7, 23 ; ; ; ;************************************************************************************** ; Useful data constants ;************************************************************************************** ; ; Constant to define a software delay of 1us. This must be adjusted to reflect the ; clock applied to KCPSM3. Every instruction executes in 2 clock cycles making the ; calculation highly predictable. The '6' in the following equation even allows for ; 'CALL delay_1us' instruction in the initiating code. ; ; delay_1us_constant = (clock_rate - 6)/4 Where 'clock_rate' is in MHz ; ; Example: For a 50MHz clock the constant value is (10-6)/4 = 11 (0B Hex). ; For clock rates below 10MHz the value of 1 must be used and the operation will ; become lower than intended. ; CONSTANT delay_1us_constant, 0B ; ; ; ;ASCII table ; CONSTANT character_a, 61 CONSTANT character_b, 62 CONSTANT character_c, 63 CONSTANT character_d, 64 CONSTANT character_e, 65 CONSTANT character_f, 66 CONSTANT character_g, 67 CONSTANT character_h, 68 CONSTANT character_i, 69 CONSTANT character_j, 6A CONSTANT character_k, 6B CONSTANT character_l, 6C CONSTANT character_m, 6D CONSTANT character_n, 6E CONSTANT character_o, 6F CONSTANT character_p, 70 CONSTANT character_q, 71 CONSTANT character_r, 72 CONSTANT character_s, 73 CONSTANT character_t, 74 CONSTANT character_u, 75 CONSTANT character_v, 76 CONSTANT character_w, 77 CONSTANT character_x, 78 CONSTANT character_y, 79 CONSTANT character_z, 7A CONSTANT character_A, 41 CONSTANT character_B, 42 CONSTANT character_C, 43 CONSTANT character_D, 44 CONSTANT character_E, 45 CONSTANT character_F, 46 CONSTANT character_G, 47 CONSTANT character_H, 48 CONSTANT character_I, 49 CONSTANT character_J, 4A CONSTANT character_K, 4B CONSTANT character_L, 4C CONSTANT character_M, 4D CONSTANT character_N, 4E CONSTANT character_O, 4F CONSTANT character_P, 50 CONSTANT character_Q, 51 CONSTANT character_R, 52 CONSTANT character_S, 53 CONSTANT character_T, 54 CONSTANT character_U, 55 CONSTANT character_V, 56 CONSTANT character_W, 57 CONSTANT character_X, 58 CONSTANT character_Y, 59 CONSTANT character_Z, 5A CONSTANT character_0, 30 CONSTANT character_1, 31 CONSTANT character_2, 32 CONSTANT character_3, 33 CONSTANT character_4, 34 CONSTANT character_5, 35 CONSTANT character_6, 36 CONSTANT character_7, 37 CONSTANT character_8, 38 CONSTANT character_9, 39 CONSTANT character_colon, 3A CONSTANT character_fullstop, 2E CONSTANT character_semi_colon, 3B CONSTANT character_minus, 2D CONSTANT character_plus, 2B CONSTANT character_comma, 2C CONSTANT character_less_than, 3C ;'<' CONSTANT character_greater_than, 3E ;'>' CONSTANT character_open, 28 ;'(' CONSTANT character_close, 29 ;')' CONSTANT character_divide, 2F ;'/' CONSTANT character_equals, 3D CONSTANT character_space, 20 CONSTANT character_CR, 0D ;carriage return CONSTANT character_LF, 0A ;line feed CONSTANT character_question, 3F ;'?' CONSTANT character_dollar, 24 CONSTANT character_exclaim, 21 ;'!' CONSTANT character_BS, 08 ;Back Space command character CONSTANT character_XON, 11 ;Flow control ON CONSTANT character_XOFF, 13 ;Flow control OFF ; ; ;************************************************************************************** ; Initialise the system and welcome message ;************************************************************************************** ; cold_start: CALL DS_wire_init ;Ensure DS_wire is not driven (pulled High) CALL delay_1s ;Allow everything to settle! welcome_start: CALL send_welcome ;start up message and version number ; ; ;************************************************************************************** ; Reset Main menu and command selection ;************************************************************************************** ; ; The main program allows you to use four of the DS2432 memory and SHA function ; commands. A simple menu is displayed and you are guided to enter more information ; when required. All the communication and protocol required to get the DS2432 ready ; to receive memory and SHA function commands has been automated although information ; is displayed to indicate the procedures being executed. ; ; Before any memory and function commands are available a master reset and read ROM ; command must be issued. ; warm_start: CALL send_CR CALL send_CR CALL DS_init_regular_mode ;master reset JUMP C, warm_start ;repeat reset if no presence pulse detected CALL read_ROM_command ;read ROM command and display results ; ; After a valid ROM command the DS2432 specific memory commands and SHA-1 ; functions become accessible. This program assumes that the ROM command did ; 'Pass' so you will need to check yourself. If this program automatically ; reset the DS2432 and tried again and there was a fault it would just cause ; the display to roll continuously and not be very informative! ; ; Each of the DS2432 commands selected from the menu will require the master reset ; and read ROM command to be repeated before being able to proceed with the next ; memory or SHA-1 function. This is automated by the program. ; ; DS2432_menu: CALL send_DS2432_menu ;Menu and command selection CALL send_CR ; DS2432_prompt: CALL send_CR ;prompt for user input CALL send_CR LOAD UART_data, character_greater_than ;prompt for input CALL send_to_UART CALL read_upper_case COMPARE s0, character_1 ;test for commands and execute as required JUMP Z, write_scratchpad_command COMPARE s0, character_2 JUMP Z, read_scratchpad_command COMPARE s0, character_3 JUMP Z, load_first_secret_command COMPARE s0, character_4 JUMP Z, read_auth_page_command CALL send_CR ;no valid command input LOAD UART_data, character_question ;display ??? CALL send_to_UART CALL send_to_UART CALL send_to_UART JUMP DS2432_prompt ;Try again! ; ; ; ; ;************************************************************************************** ; DS2432 Read ROM Command. ;************************************************************************************** ; ; The read ROM command (33 hex) allows the 8-bit family code, 48-bit unique serial ; number and 8-bit CRC to be read from the DS2432 device. ; ; This routine reads the values and places them in KCPSM3 scratch pad memory ; locations for future reference. These locations should be defined with constants ; as follows and MUST be in consecutive ascending locations. ; ; family_code ; Location to store family code which should be 33 hex ; serial_number0 to serial_number5 ; 6 bytes to hold 48-bit serial number (LS-byte first). ; read_ROM_CRC ; 8-bit CRC value for the above data. ; ; ; The routine also displays the values read and performs a verification of the ; 8-bit CRC displaying a 'Pass' or 'Fail' message as appropriate. ; read_ROM_command: LOAD s3, 33 ;Read ROM Command CALL write_byte_slow ;transmit command LOAD s5, family_code ;memory pointer read_ROM_loop: CALL read_byte_slow ;read response into s3 STORE s3, (s5) ;store value COMPARE s5, read_ROM_CRC ;8-bytes to read JUMP Z, display_ROM ADD s5, 01 JUMP read_ROM_loop display_ROM: CALL send_CR CALL send_code ;'code=' to display family code FETCH s0, family_code CALL send_hex_byte CALL send_CR CALL send_sn ;'s/n=' to display family code LOAD s5, serial_number5 ;memory pointer starting MS-byte first disp_serial_loop: FETCH s0, (s5) CALL send_hex_byte COMPARE s5, serial_number0 JUMP Z, end_serial SUB s5, 01 JUMP disp_serial_loop end_serial: CALL send_CR CALL send_crc ;'CRC=' to display CRC value FETCH s0, read_ROM_CRC CALL send_hex_byte CALL send_CR CALL compute_CRC8 ;compute CRC value in s0 FETCH s1, read_ROM_CRC ;compare with received value COMPARE s0, s1 JUMP NZ, crc8_fail CALL send_Pass RETURN crc8_fail: CALL send_Fail RETURN ; ; ; ;************************************************************************************** ; DS2432 Load First Secret Command. ;************************************************************************************** ; ; This command will only be valid if the write scratchpad memory command has previously ; been used to define the new secret to be stored at address 0080. ; ; The Load First Secret Command (5A hex) will only copy the scratchpad contents into ; ; the EEPROM array of the DS2432 if the address was correctly specified in the ; write scratchpad command. This routine will assume that the address specified ; was 0080. If everything is OK with the programming of the secret, the DS2432 responds ; with 'AA' hex after the command and this routine will report 'Pass'. You can further ; check using a read scratchpad command and look to see if E/S has changed from '5F' ; to 'DF' which indicates the successful write. ; ; Note that this program defines the secret to be used by the PicoBlaze SHA-1 algorithm ; in the constants 'secret0' through to 'secret7'. Only if you program the DS2432 ; with a matching secret will the read authenticated message command result in a ; 'Pass' being reported for the MAC. This Load First Secret Command routine deliberately ; does not update the secret used by the PicoBlaze SHA-1 algorithm so that you can ; prove that only a DS2432 with the matching secret will generate matching MAC ; responses. ; ; ; load_first_secret_command: LOAD s3, 5A ;Load First Secret Command CALL write_byte_slow ;transmit command LOAD s3, 80 ;TA1 value for secret = 80 hex CALL write_byte_slow LOAD s3, 00 ;TA2 value for secret = 00 hex CALL write_byte_slow LOAD s3, 5F ;E/S value before writing = 5F hex CALL write_byte_slow CALL delay_20ms ;write takes place in 10ms CALL send_CR CALL send_secret CALL send_space CALL read_byte_slow ;read data into s3 COMPARE s3, AA ;test response JUMP Z, secret_pass CALL send_Fail JUMP warm_start secret_pass: CALL send_Pass JUMP warm_start ; ; ;************************************************************************************** ; DS2432 Write Scratchpad Memory Command. ;************************************************************************************** ; ; The write scratchpad memory command (0F hex) allows 8-bytes of data to be written ; together with a target address for final storage in the main memory map. The ; DS2432 scratch pad is also used to define a 3 byte 'challenge' used in the ; SHA-1 algorithm. ; ; The DS2432 provides an initial confirmation of the write by returning a 16-bit CRC ; value which KCPSM3 tests. The CRC is computed based on the command, address and ; data transmitted (11 bytes). PicoBlaze also computes the CRC and and tests this ; against the value received from the DS2432. ; ; This routine prompts the user to enter the 16-bit target address is to be loaded ; into the target address registers TA2 and TA1 in the DS2432 device. Note that only ; address values below 0090 hex are valid. If the address is too high, then the ; DS2432 aborts the command and this routine will too. ; ; Also note that the address will be forced internally to the DS2432 to match an ; 8-byte boundary address in which the least significant 3-bits are reset to '000' ; regardless of the address provided. The CRC still reflects the transmitted address. ; ; After providing a valid address, the routine then prompts the user to enter ; 8 bytes of data which are written to the DS2432. ; ; ; write_scratchpad_command: CALL clear_CRC16 ;prepare CRC registers [sE,sD] LOAD s3, 0F ;write scratchpad memory Command CALL write_byte_slow ;transmit command CALL compute_CRC16 ;compute CRC for value in 's3' wsc_addr_loop: CALL send_address ;obtain 16-bit address 0000 to FFFF in [s5,s4] CALL obtain_8bits JUMP C, wsc_addr_loop ;bad input address LOAD s5, s0 CALL obtain_8bits JUMP C, wsc_addr_loop ;bad input address LOAD s4, s0 LOAD s3, s4 ;transmit target address TA1 (LS-Byte) CALL write_byte_slow CALL compute_CRC16 ;compute CRC for value in 's3' LOAD s3, s5 ;transmit target address TA2 (MS-Byte) CALL write_byte_slow CALL compute_CRC16 ;compute CRC for value in 's3' COMPARE s5, 00 ;check address less than 0090 hex JUMP NZ, warm_start ;DS2432 aborts command and so do we! COMPARE s4, 90 ;no need to read data bytes. JUMP NC, warm_start LOAD s4, 00 ;initialise byte counter wsc_data_loop: CALL send_data ;obtain a byte of data LOAD UART_data, s4 ;display which byte requested ADD UART_data, character_0 ;convert to ASCII CALL send_to_UART CALL send_equals CALL obtain_8bits JUMP C, wsc_data_loop ;bad input data LOAD s3, s0 ;transmit byte CALL write_byte_slow CALL compute_CRC16 ;compute CRC for value in 's3' ADD s4, 01 ;count bytes COMPARE s4, 08 JUMP NZ, wsc_data_loop CALL send_CR CALL read_send_test_CRC16 ;read, display and test CRC value JUMP warm_start ; ; ; ;************************************************************************************** ; DS2432 Read Scratchpad Memory Command. ;************************************************************************************** ; ; The read scratchpad memory command (AA hex) allows the 8-bytes of data previously ; to be written into the scratchpad memory to be read back for verification together with ; the target address, a transfer status register (E/S) and a 16-bit CRC value. ; ; The 16-bit CRC is formed of the command byte, address TA1 and TA2, E/S byte and 8 data ; bytes as transmitted (12 bytes). These may not be the same as the values provided ; during a previous write to scratchpad memory. PicoBlaze also computes the CRC and ; and tests this against the value received from the DS2432. ; ; The 8 bytes of data are also copied to PicoBlaze memory at locations defined by the ; constants 'scratchpad0' to 'scratchpad7'. Three bytes are used as a 'challenge' ; by the SHA-1 algorithm. ; ; ; read_scratchpad_command: CALL clear_CRC16 ;prepare CRC registers [sE,sD] LOAD s3, AA ;read scratchpad memory Command CALL write_byte_slow ;transmit command CALL compute_CRC16 ;compute CRC for value in 's3' CALL send_address ;display 'Address=' CALL read_byte_slow ;read address into [s5,s4] CALL compute_CRC16 ;compute CRC for value in 's3' LOAD s4, s3 CALL read_byte_slow CALL compute_CRC16 ;compute CRC for value in 's3' LOAD s5, s3 LOAD s0, s5 ;display address CALL send_hex_byte LOAD s0, s4 CALL send_hex_byte CALL send_ES ;display 'E/S=' CALL read_byte_slow ;read E/S register CALL compute_CRC16 ;compute CRC for value in 's3' LOAD s0, s3 ;display value CALL send_hex_byte CALL send_data ;display 'Data=' CALL send_equals LOAD s4, scratchpad0 ;pointer to memory and byte counter rsc_loop: CALL send_space CALL read_byte_slow ;read data byte CALL compute_CRC16 ;compute CRC for value in 's3' STORE s3, (s4) ;store value in memory LOAD s0, s3 ;display value CALL send_hex_byte COMPARE s4, scratchpad7 ;count bytes JUMP Z, end_rsc_data_loop ADD s4, 01 JUMP rsc_loop end_rsc_data_loop: CALL send_CR CALL read_send_test_CRC16 ;read, display and test CRC value JUMP warm_start ; ; ; ; ; ;************************************************************************************** ; DS2432 Read Authenticated Page Command. ;************************************************************************************** ; ; The read authenticated page command (A5 hex) allows the 8-byte secret to be tested ; without it actually being read (which would obviously give away the secret!). ; ; This routine has been written to work with page 0 but could easily be changed and ; is documented below. During the first part of the command, the 32 bytes ; contained in the page are read back from the DS2432 and these are used in ; the preparation of the table required for the for SHA-1 algorithm. Other values ; stored in the table are the secret, serial number of the DS2432, family code, some ; constants, 4-bits of the page address and a 3 byte 'challenge' currently set into ; the DS2432 scratchpad memory. ; ; NOTE - The read scratchpad command must be executed before this routine in order ; that the 3 byte 'challenge' of scratchpad memory is known to PicoBlaze. ; ; During this command, two 16-bit CRC values are generated which PicoBlaze also ; computes and tests. The first is formed of the command byte, address TA1 and TA2, ; all the bytes of the page read and an 'FF' byte. The second is formed of the 20 ; bytes of the 160-but message authentication code (MAC). ; ; ; Preparing the table. ; ; The table is stored in the external 'Wt' buffer and must first be initialised with the ; 16 'M' words (32-bit words each requiring 4 bytes). This is achieved by shifting in ; each word in sequence. Storing each word most significant byte first is a natural ; fit with the reading of the page data from the DS2432 and the way each 'M' word ; is organised. Notice how this causes least significant bytes to be swapped with most ; significant bytes! ; ; [31:24] [23:16] [15:8] [7:0] ; ; M0 = [secret0 , secret1 , secret2 , secret3 ] ; M1 = [page_data0 , page_data1 , page_data2 , page_data3 ] ; M2 = [page_data4 , page_data5 , page_data6 , page_data7 ] ; M3 = [page_data8 , page_data9 , page_data10, page_data11] ; M4 = [page_data12, page_data13, page_data14, page_data15] ; M5 = [page_data16, page_data17, page_data18, page_data19] ; M6 = [page_data20, page_data21, page_data22, page_data23] ; M7 = [page_data24, page_data25, page_data26, page_data27] ; M8 = [page_data28, page_data29, page_data30, page_data31] ; M9 = [ FF , FF , FF , FF ] ; M10 = [ 40 , 33 , serial_num0, serial_num1] ; M11 = [serial_num2, serial_num3, serial_num4, serial_num5] ; M12 = [secret4 , secret5 , secret6 , secret7 ] ; M13 = [scratchpad4, scratchpad5, scratchpad6, 80 ] ; M14 = [ 00 , 00 , 00 , 00 ] ; M15 = [ 00 , 00 , 01 , B8 ] ; ; In M10, the '33' is the family code and the '40' is made up of a constant bit ; pattern '0100' and then bits [8:5] of the page address. This gives 4 possible values ; for this byte during a Read Authenticated Page Command, but this routine is currently ; fixed to work with page 0 only. ; 40 - page 0 ; 41 - page 1 ; 42 - page 2 ; 43 - page 3 ; ; M13 contains the 3 byte challenge from the scratch pad memory. This assumes that a ; read scratchpad command has previously been used and the bytes held in the DS2432 ; scratchpad match those held in the PicoBlaze memory. ; ; ; The 160-bit Message Authentication Code (MAC) is computed from the table using the SHA-1 ; algorithm. This algorithm actually results in 5 variables 'A', 'B', 'C', 'D' and 'E' ; which are 32-bit values each formed of 4 bytes. The MAC is the concatenation of ; the variables. To match the same order in which the Read Authenticated Page Command ; sends the MAC, the variables must be read in the order 'E', 'D', 'C', 'B' and 'A' and ; with the least significant byte of each variable first. ; ; ; ; ; read_auth_page_command: LOAD s0, secret0 ;store M0 (secret 0, 1, 2 and 3) in Wt buffer. OUTPUT s0, W_word_write_port LOAD s0, secret1 OUTPUT s0, W_word_write_port LOAD s0, secret2 OUTPUT s0, W_word_write_port LOAD s0, secret3 OUTPUT s0, W_word_write_port ; ;Start of DS2432 command ; CALL clear_CRC16 ;prepare CRC registers [sE,sD] LOAD s3, A5 ;read authenticated page command CALL write_byte_slow ;transmit command CALL compute_CRC16 ;compute CRC for value in 's3' LOAD s5, 00 ;set address for page 0 LOAD s4, 00 ; [TA2,TA1]=0000 hex LOAD s3, s4 ;transmit TA1 CALL write_byte_slow CALL compute_CRC16 ;compute CRC for value in 's3' LOAD s3, s5 ;transmit TA2 CALL write_byte_slow CALL compute_CRC16 ;compute CRC for value in 's3' ; ;Read 32-bytes of data associated with page 0 ;Store these as M1 through to M8 ; rapc_line_loop: CALL send_CR LOAD s0, s5 ;display 16-bit address CALL send_hex_byte LOAD s0, s4 CALL send_hex_byte CALL send_space CALL send_space rapc_data_loop: CALL send_space CALL read_byte_slow ;read data into s3 CALL compute_CRC16 ;compute CRC for value in 's3' OUTPUT s3, W_word_write_port ;store as 'M' word LOAD s0, s3 ;display byte CALL send_hex_byte ADD s4, 01 ;increment address ADDCY s5, 00 TEST s4, 07 ;test for 8-byte boundary JUMP NZ, rapc_data_loop COMPARE s4, 20 ;test for last address JUMP NZ, rapc_line_loop CALL send_CR ; ;Read one byte that should be value FF hex ; CALL read_byte_slow ;read data into s3 CALL compute_CRC16 ;compute CRC for value in 's3' LOAD s0, s3 ;display byte CALL send_hex_byte CALL send_CR CALL read_send_test_CRC16 ;read, display and test CRC value ; ;Complete table by stroring M9 through to M15 ; LOAD s0, FF ;W9 = FF FF FF FF LOAD s1, 04 store_W9: OUTPUT s0, W_word_write_port SUB s1, 01 JUMP NZ, store_W9 ; LOAD s0, 40 ;W10 begins with 40 for page 0 OUTPUT s0, W_word_write_port ; ;W10 ends with family code and serial number 0 and 1. ;W11 is formed of serial number 2, 3, 4 and 5. ;All of this information is in PicoBlaze memory having been read by the ;read ROM command. ; LOAD s1, family_code ;pointer to memory LOAD s2, 07 ;7 bytes to read and store next_M10_M11: FETCH s0, (s1) OUTPUT s0, W_word_write_port ADD s1, 01 ;increment pointer SUB s2, 01 JUMP NZ, next_M10_M11 ; LOAD s0, secret4 ;store M12 (secret 4, 5, 6 and 7) in Wt buffer OUTPUT s0, W_word_write_port LOAD s0, secret5 OUTPUT s0, W_word_write_port LOAD s0, secret6 OUTPUT s0, W_word_write_port LOAD s0, secret7 OUTPUT s0, W_word_write_port ; FETCH s0, scratchpad4 ;M13 uses scratchpad 4, 5, and 6 and '80' hex OUTPUT s0, W_word_write_port FETCH s0, scratchpad5 OUTPUT s0, W_word_write_port FETCH s0, scratchpad6 OUTPUT s0, W_word_write_port LOAD s0, 80 OUTPUT s0, W_word_write_port ; LOAD s0, 00 ;W14 = 00 00 00 00 W15 = 00 00 01 B8 LOAD s1, 06 store_W14_W15: OUTPUT s0, W_word_write_port SUB s1, 01 JUMP NZ, store_W14_W15 LOAD s0, 01 OUTPUT s0, W_word_write_port LOAD s0, B8 OUTPUT s0, W_word_write_port ; ;Compute the SHA-1 algorithm at the same time that the DS2432 is also computing (2ms). ; CALL compute_sha1 ; ;The 160-bit Message Authentication Code is read from the DS2432 as 20 bytes ;and compared with the concatenation of variables E, D, C, B and A in that order ;with each variable received from the DS2432 least significant byte first. ;Each received byte is also used to form a 16-bit CRC value which is tested to ;reveal any communication errors. ; ; CALL send_mac ;display 'mac=' CALL clear_CRC16 ;prepare CRC registers [sE,sD] LOAD sC, 00 ;Clear byte match counter LOAD sB, var_E0 ;start match with LS-Byte of variable 'E' mac_match_var: LOAD sA, 04 ;4 bytes to match in each variable mac_match_byte: FETCH s9, (sB) ;read variable byte from local SHA-1 CALL read_byte_slow ;read DS2432 byte into s3 CALL compute_CRC16 ;compute CRC for value in 's3' COMPARE s3, s9 ;compare MAC values JUMP NZ, display_mac_byte ;count matching bytes ADD sC, 01 ;decrement match counter display_mac_byte: LOAD s0, s3 ;display byte CALL send_hex_byte CALL send_space SUB sA, 01 ;counts bytes per variable JUMP Z, next_mac_var ADD sB, 01 JUMP mac_match_byte next_mac_var: COMPARE sB, var_A3 ;test for last byte JUMP Z, report_mac SUB sB, 07 ;point to next variable JUMP mac_match_var ; ;MAC has passed if all 20 bytes matched ; report_mac: CALL send_CR COMPARE sC, 14 ;20 bytes should have matched JUMP NZ, mac_fail CALL send_Pass JUMP read_mac_CRC mac_fail: CALL send_Fail ; ;Next two bytes received are the 16-bit CRC ;Read 16-bit CRC into [s5,s4] and send value to UART ; read_mac_CRC: CALL read_send_test_CRC16 ;read, display and test CRC value ; ;Read one byte that should be value AA hex. ; Would actually read AA hex continuously until master reset ; CALL read_byte_slow ;read data into s3 LOAD s0, s3 ;display byte CALL send_hex_byte CALL send_CR ; JUMP warm_start ; ; ;************************************************************************************** ; Compute SHA-1 Algorithm. ;************************************************************************************** ; ; Computes the SHA-1 algorithm based on the initial table of values (M0 through to M15) ; which are stored in the external Wt buffer. ; ; The SHA-1 algorithms uses 5 variables called 'A', 'B', 'C', 'D' and 'E'. Each variable ; is 32-bits and stored as 4 bytes in PicoBlaze scratch pad memory. The locations must ; be defined using constants 'var_A0' thought to 'var_E3' in ascending locations. ; ; Constants must also be used to define access to the external Wt buffer. ; ; During this process, register 'sE' is used to count iterations from 0 to 79 (4F hex). ; Other registers are consistently grouped as follows to support 32-bit operations. ; ; Register set [s5,s4,s3,s2] is used as a temporary 32-bit word ; Register set [s9,s8,s7,s6] is used as a temporary 32-bit word ; Register set [sD,sC,sB,sA] is used as a temporary 32-bit word ; ; ; Initialise the 32-bit variables ; ; compute_sha1: LOAD s0, 01 ;A=67452301 STORE s0, var_A0 LOAD s0, 23 STORE s0, var_A1 LOAD s0, 45 STORE s0, var_A2 LOAD s0, 67 STORE s0, var_A3 LOAD s0, 89 ;B=EFCDAB89 STORE s0, var_B0 LOAD s0, AB STORE s0, var_B1 LOAD s0, CD STORE s0, var_B2 LOAD s0, EF STORE s0, var_B3 LOAD s0, FE ;C=98BADCFE STORE s0, var_C0 LOAD s0, DC STORE s0, var_C1 LOAD s0, BA STORE s0, var_C2 LOAD s0, 98 STORE s0, var_C3 LOAD s0, 76 ;D=10325476 STORE s0, var_D0 LOAD s0, 54 STORE s0, var_D1 LOAD s0, 32 STORE s0, var_D2 LOAD s0, 10 STORE s0, var_D3 LOAD s0, F0 ;E=C3D2E1F0 STORE s0, var_E0 LOAD s0, E1 STORE s0, var_E1 LOAD s0, D2 STORE s0, var_E2 LOAD s0, C3 STORE s0, var_E3 ; ; LOAD sE, 00 ;reset iteration counter ; ; ;Compute ft(B,C,D) in register set [s5,s4,s3,s2] and then add constant Kt. ; ;Iterations 0 to 19 - process type 1 ; ft = (B and C) or ((not B) and D) ; Then the constant Kt=5A827999 will be added ; ;Iterations 20 to 39 and iterations 60 to 79 - process type 2 ; ft = B xor C xor D ; Then the constant Kt=6ED9EBA1 will be added for iterations 20 to 39 ; Then the constant Kt=CA62C1D6 will be added for iterations 60 to 79 ; ;Iterations 40 to 59 - process type 3 ; ft = (B and C) or (B and D) or (C and D) ; Then the constant Kt=8F1BBCDC will be added ; next_sha1_iteration: FETCH s5, var_B3 ;B in [s5,s4,s3,s2] FETCH s4, var_B2 FETCH s3, var_B1 FETCH s2, var_B0 CALL fetch_C ;C in [s9,s8,s7,s6] FETCH sD, var_D3 ;D in [sD,sC,sB,sA] FETCH sC, var_D2 FETCH sB, var_D1 FETCH sA, var_D0 ; ;Determine process type ; COMPARE sE, 14 ;set carry flag for iterations <20 JUMP C, ft_type1 COMPARE sE, 28 ;set carry flag for iterations <40 JUMP C, ft_type2 COMPARE sE, 3C ;set carry flag for iterations <60 JUMP C, ft_type3 ; ; ft = B xor C xor D ; ; B xor C = B xor C ; [s5,s4,s3,s2] = [s5,s4,s3,s2] xor [s9,s8,s7,s6] ; ; B xor C xor D = (B xor C) xor D ; [s5,s4,s3,s2] = [s5,s4,s3,s2] xor [sD,sC,sB,sA] ; ; ft_type2: XOR s5, s9 ;B xor C in [s5,s4,s3,s2] XOR s4, s8 XOR s3, s7 XOR s2, s6 XOR s5, sD ;(B xor C) xor D in [s5,s4,s3,s2] XOR s4, sC XOR s3, sB XOR s2, sA COMPARE sE, 3C ;set carry flag for iterations <60 JUMP NC, Kt_CA62C1D6 ADD s2, A1 ;add Kt=6ED9EBA1 ADDCY s3, EB ADDCY s4, D9 ADDCY s5, 6E JUMP compute_TMP Kt_CA62C1D6: ADD s2, D6 ;add Kt=CA62C1D6 ADDCY s3, C1 ADDCY s4, 62 ADDCY s5, CA JUMP compute_TMP ; ; ft = (B and C) or ((not B) and D) ; ; B and C = C and B ; [s9,s8,s7,s6] = [s9,s8,s7,s6] and [s5,s4,s3,s2] ; ; not B = B xor FFFFFFFF ; [s5,s4,s3,s2] = [s5,s4,s3,s2] xor [FF,FF,FF,FF] ; ; (not B) and D = (not B) and D ; [s5,s4,s3,s2] = [s5,s4,s3,s2] and [sD,sC,sB,sA] ; ; ;(B and C) or ((not B) and D) = ((not B) and D) or (B and C) ; [s5,s4,s3,s2] = [s5,s4,s3,s2] or [s9,s8,s7,s6] ; ft_type1: AND s9, s5 ;B and C in [s9,s8,s7,s6] AND s8, s4 AND s7, s3 AND s6, s2 XOR s5, FF ;(not B) in [s5,s4,s3,s2] XOR s4, FF XOR s3, FF XOR s2, FF AND s5, sD ;((not B) and D) in [s5,s4,s3,s2] AND s4, sC AND s3, sB AND s2, sA OR s5, s9 ;(B and C) or ((not B) and D) in [s5,s4,s3,s2] OR s4, s8 OR s3, s7 OR s2, s6 ADD s2, 99 ;add Kt=5A827999 ADDCY s3, 79 ADDCY s4, 82 ADDCY s5, 5A JUMP compute_TMP ; ;Routine to fetch variable 'C' into register set [s9,s8,s7,s6] ; fetch_C: FETCH s9, var_C3 FETCH s8, var_C2 FETCH s7, var_C1 FETCH s6, var_C0 RETURN ; ; ft = (B and C) or (B and D) or (C and D) ; ; B and C = C and B ; [s9,s8,s7,s6] = [s9,s8,s7,s6] and [s5,s4,s3,s2] ; ; B and D = B and D ; [s5,s4,s3,s2] = [s5,s4,s3,s2] and [sD,sC,sB,sA] ; ; (B and C) or (B and D) = (B and D) or (B and C) ; [s5,s4,s3,s2] = [s5,s4,s3,s2] or [s9,s8,s7,s6] ; ; read C again into [s9,s8,s7,s6] ; ; C and D = C and D ; [s9,s8,s7,s6] = [s9,s8,s7,s6] and [sD,sC,sB,sA] ; ; ((B and C) or (B and D)) or (C and D) = ((B and C) or (B and D)) or (C and D) ; [s5,s4,s3,s2] = [s5,s4,s3,s2] or [s9,s8,s7,s6] ; ft_type3: AND s9, s5 ;(B and C) in [s9,s8,s7,s6] AND s8, s4 AND s7, s3 AND s6, s2 AND s5, sD ;(B and D) in [s5,s4,s3,s2] AND s4, sC AND s3, sB AND s2, sA OR s5, s9 ;(B and C) or (B and D) in [s5,s4,s3,s2] OR s4, s8 OR s3, s7 OR s2, s6 CALL fetch_C ;C in [s9,s8,s7,s6] AND s9, sD ;(C and D) in [s9,s8,s7,s6] AND s8, sC AND s7, sB AND s6, sA OR s5, s9 ;(B and C) or (B and D) or (C and D) in [s5,s4,s3,s2] OR s4, s8 OR s3, s7 OR s2, s6 ADD s2, DC ;add Kt=8F1BBCDC ADDCY s3, BC ADDCY s4, 1B ADDCY s5, 8F ; ;Add variable 'E' to [s5,s4,s3,s2] ; compute_TMP: FETCH s0, var_E0 ADD s2, s0 FETCH s0, var_E1 ADDCY s3, s0 FETCH s0, var_E2 ADDCY s4, s0 FETCH s0, var_E3 ADDCY s5, s0 ; ;Add variable 'A' rotated left 5 places ; FETCH s9, var_A3 ;A in [s9,s8,s7,s6] FETCH s8, var_A2 FETCH s7, var_A1 FETCH s6, var_A0 LOAD s0, 05 ;rotate left 5 places CALL rotate_word_left_N_places ADD s2, s6 ;add to TMP ADDCY s3, s7 ADDCY s4, s8 ADDCY s5, s9 ; ; ;Compute Wt in register set [s9,s8,s7,s6] ; Value computed is also stored back in the external buffer for ; use in later iterations as well as being added to TMP. ; ;Iterations 0 to 15 ; Wt = Mt ; This only requires Wt-16 to be read and then shifted back into the buffer again. ; ;Iterations 0 to 15 ; Wt = rotate_left_1_place(Wt-3 xor Wt-8 xor Wt-14 xor Wt-16) ; This requires all data values to be read first. Then XORed and rotated before ; shifting the new Wt word into the buffer. ; ; INPUT s9, Wt_minus16_byte3_read_port ;Read Wt-16 value INPUT s8, Wt_minus16_byte2_read_port INPUT s7, Wt_minus16_byte1_read_port INPUT s6, Wt_minus16_byte0_read_port COMPARE sE, 10 ;set carry flag for iterations 0 to 15 JUMP C, store_Wt ; ;Read other Wt words and perform XOR ; INPUT s0, Wt_minus14_byte3_read_port ;XOR with Wt-14 value XOR s9, s0 INPUT s0, Wt_minus14_byte2_read_port XOR s8, s0 INPUT s0, Wt_minus14_byte1_read_port XOR s7, s0 INPUT s0, Wt_minus14_byte0_read_port XOR s6, s0 INPUT s0, Wt_minus8_byte3_read_port ;XOR with Wt-8 value XOR s9, s0 INPUT s0, Wt_minus8_byte2_read_port XOR s8, s0 INPUT s0, Wt_minus8_byte1_read_port XOR s7, s0 INPUT s0, Wt_minus8_byte0_read_port XOR s6, s0 INPUT s0, Wt_minus3_byte3_read_port ;XOR with Wt-3 value XOR s9, s0 INPUT s0, Wt_minus3_byte2_read_port XOR s8, s0 INPUT s0, Wt_minus3_byte1_read_port XOR s7, s0 INPUT s0, Wt_minus3_byte0_read_port XOR s6, s0 CALL rotate_word_left ;rotate XORed word left by one place ; ;Store new Wt value in external buffer ; store_Wt: OUTPUT s9, W_word_write_port OUTPUT s8, W_word_write_port OUTPUT s7, W_word_write_port OUTPUT s6, W_word_write_port ; ;Add new computed Wt value to TMP in [s5,s4,s3,s2] ; ADD s2, s6 ADDCY s3, s7 ADDCY s4, s8 ADDCY s5, s9 ; ;TMP is now complete in [s5,s4,s3,s2] ; ; ;copy values ; E <= D ; D <= C ; C <= B (this will need to be rotated 30 places afterwards) ; B <= A ; LOAD sD, 04 ;4 bytes per word to copy copy_var_loop: LOAD sC, var_E3 LOAD sB, var_E2 move_var_loop: FETCH sA, (sB) STORE sA, (sC) SUB sC, 01 SUB sB, 01 COMPARE sC, var_A0 JUMP NZ, move_var_loop SUB sD, 01 JUMP NZ, copy_var_loop ; ;rotate 'C' (the previous 'B') left 30 places ; CALL fetch_C ;C in [s9,s8,s7,s6] LOAD s0, 1E ;rotate left 30 places CALL rotate_word_left_N_places STORE s9, var_C3 STORE s8, var_C2 STORE s7, var_C1 STORE s6, var_C0 ; ; A <= TMP ; STORE s5, var_A3 STORE s4, var_A2 STORE s3, var_A1 STORE s2, var_A0 ; ;count iterations ; COMPARE sE, 4F ;test for last iteration = 79 decimal (4F hex) RETURN Z ADD sE, 01 JUMP next_sha1_iteration ; ; Routine to rotate left the contents of Register set [s9,s8,s7,s6] ; by the number of places specified in register 's0'. ; rotate_word_left_N_places: CALL rotate_word_left SUB s0, 01 JUMP NZ, rotate_word_left_N_places RETURN ; ; Routine to rotate left the contents of Register set [s9,s8,s7,s6] ; by one place. ; rotate_word_left: TEST s9, 80 ;test MSB of word SLA s6 SLA s7 SLA s8 SLA s9 RETURN ; ;************************************************************************************** ; Compute 8-bit CRC used by DS2432. ;************************************************************************************** ; ; The DS2432 computes an 8-bit CRC using the polynomial X8 + X5 + X4 + 1. ; See the DS2432 data sheet for full details. ; ; Test input value of value 00 00 00 01 B8 1C 02 ; should produce CRC=A2. ; ; This routine computes the same CRC based on the values stored in the KCPSM3 ; scratch pad memory by the read ROM command. The result is returned in register s0. ; ; Registers used s0,s1,s2,s3,s4,s5,s6,s7,s8,s9 ; ; ; Start by loading family code and serial number (56-bits) into register set ; [s9,s8,s7,s6,s5,s4,s3] so that it can be shifted out LSB first. ; ; compute_CRC8: FETCH s3, family_code FETCH s4, serial_number0 FETCH s5, serial_number1 FETCH s6, serial_number2 FETCH s7, serial_number3 FETCH s8, serial_number4 FETCH s9, serial_number5 LOAD s2, 38 ;56 bits to shift (38 hex) LOAD s0, 00 ;clear CRC value crc8_loop: LOAD s1, s0 ;copy current CRC value XOR s1, s3 ;Need to know LSB XOR next input bit TEST s1, 01 ;test result of XOR in LSB JUMP NC, crc8_shift XOR s0, 18 ;compliment bits 3 and 4 of CRC crc8_shift: SR0 s1 ;Carry gets LSB XOR next input bit SRA s0 ;shift Carry into MSB to form new CRC value SR0 s9 ;shift input value SRA s8 SRA s7 SRA s6 SRA s5 SRA s4 SRA s3 SUB s2, 01 ;count iterations JUMP NZ, crc8_loop RETURN ; ; ; ;************************************************************************************** ; Clear or Compute 16-bit CRC used by DS2432. ;************************************************************************************** ; ; The DS2432 computes a 16-bit CRC using the polynomial X16 + X15 + X2 + 1. ; See the DS2432 data sheet for full details. ; ; Note that the value formed in the CRC shift register MUST BE INVERTED to give the ; same value as that sent from the DS2432 during scratchpad write, scratchpad read ; and read auth page commands. ; ; The 16-bit CRC is computed using a different number of bytes depending on the ; command. This routine has been written such that the CRC can be computed one ; byte at a time. The byte to be processed should be provided in register 's3' ; and the contents of this register are preserved. ; ; This routine computes the 16-bit CRC in the register pair [sE,sD] and these ; registers must not be disturbed between calls of this routine. ; ; Before starting a CRC computation the 'clear_CRC16' should be used. ; ; Registers used s0,s1,s3,sD,sE ; s3 is preserved. ; sD and sE should not be disturbed between calls if CRC value is required. ; ; clear_CRC16: LOAD sE, 00 ;[sE,sD]=0000 LOAD sD, 00 RETURN ; compute_CRC16: LOAD s1, 08 ;8-bits to shift crc16_loop: LOAD s0, sD ;copy current CRC value XOR s0, s3 ;Need to know LSB XOR next input bit TEST s0, 01 ;test result of XOR in LSB JUMP NC, crc16_shift XOR sD, 02 ;compliment bit 1 of CRC XOR sE, 40 ;compliment bit 14 of CRC crc16_shift: SR0 s0 ;Carry gets LSB XOR next input bit SRA sE ;shift Carry into MSB to form new CRC value SRA sD RR s3 ;shift input value SUB s1, 01 ;count bits JUMP NZ, crc16_loop ;next bit RETURN ; ; ;************************************************************************************** ; Read 16-bit CRC from DS2432, send value received to UART and test result. ;************************************************************************************** ; ; The computed CRC value for comparison must be in register pair [sE,sD] ; read_send_test_CRC16: CALL read_byte_slow ;read 16-bit CRC into [s5,s4] LOAD s4, s3 CALL read_byte_slow LOAD s5, s3 CALL send_crc ;'crc=' to display CRC value LOAD s0, s5 CALL send_hex_byte LOAD s0, s4 CALL send_hex_byte CALL send_CR XOR sD, FF ;1's complement the computed CRC value XOR sE, FF COMPARE s4, sD ;test received value with computed value JUMP NZ, crc16_fail COMPARE s5, sE JUMP NZ, crc16_fail CALL send_Pass ;display 'Pass' with carriage return RETURN crc16_fail: CALL send_Fail ;display 'Fail' with carriage return RETURN ; ; ;************************************************************************************** ; Initialise the DS2432 1-wire interface. ;************************************************************************************** ; ; The 1-wire interface is an open-collector communication scheme employing an external ; pull-up resistor of 680 Ohms. ; ; The hardware section of this translates the one bit signal from PicoBlaze such that ; when this signal is Low the output is driven Low, but when it is High, it turns off ; the output buffer and the signal is pulled High externally. ; ; This initialisation routine simply ensures that the line is High after configuration. ; It is vital that DS_wire is generally in the High state because it is the only way in ; which the DS2432 device derives power to operate. ; ; Registers used s0 ; DS_wire_init: LOAD s0, DS_wire OUTPUT s0, DS_wire_out_port RETURN ; ; ;************************************************************************************** ; DS2432 initialisation - Regular Speed. ;************************************************************************************** ; ; The initialisation sequence must be performed before any communication can be ; made with the DS2432 device. This involves the application of an active Low master ; reset pulse. ; ; The regular (slow) speed communication is established by transmitting an active ; Low reset pulse for a duration of at least 480us. This design generates a 500us pulse. ; ; The DS2432 acknowledges the reset and the setting of regular mode by generating an ; active Low 'Rx Presence Pulse'. This presence pulse can start 15 to 60us after the ; reset pulse and will end between 120 and 300us after the reset pulse. ; ; To confirm that regular mode has been set, this routine confirms that the presence pulse ; is active only after 60us have elapsed since the reset pulse. This ensures that the ; faster presence pulse of overdrive mode can not be detected. ; ; The carry flag will be set if no valid presence pulse was received (wire remained High) and ; can be used to indicate an initialisation failure or success. ; ; The routine only completes 300us after the presence pulse to ensure the DS2432 has ; completed the presence pulse and is ready for the first operation. ; ; Registers used s0,s1,s2 ; DS_init_regular_mode: LOAD s0, 00 ;transmit reset pulse OUTPUT s0, DS_wire_out_port ;Delay of 500us is equivalent to 12500 instructions at 50MHz. ;This delay loop is formed of 28 instructions requiring 446 repetitions. LOAD s2, 01 ;[s3,s2]=445 decimal (01BD hex) LOAD s1, BD rm_wait_500us: CALL delay_1us ;25 instructions including CALL SUB s1, 01 ;decrement delay counter SUBCY s2, 00 JUMP NC, rm_wait_500us ;repeat until -1 LOAD s0, 01 ;end of regular reset pulse OUTPUT s0, DS_wire_out_port ;Delay of 60us is equivalent to 1500 instructions at 50MHz. ;This delay and is formed of 27 instructions requiring 56 repetitions. LOAD s1, 38 ;56 (38 hex) rm_wait_60us: CALL delay_1us ;25 instructions including CALL SUB s1, 01 ;decrement delay counter JUMP NZ, rm_wait_60us ;repeat until zero ;The DS_wire is now checked at approximately 1us intervals for the next 240us looking ;to detect an active Low presence pulse. The 240us is equivalent to 6000 instructions ;at 50MHz and this polling loop is formed of 33 instructions requiring 182 repetitions. LOAD s2, 01 ;set bit which will be reset by a presence pulse LOAD s1, B6 ;182 (B6 hex) rm_poll_240us: CALL delay_1us ;25 instructions including CALL CALL read_DS_wire ;read wire - 5 instructions including CALL AND s2, s0 ;clear flag if DS_wire was Low SUB s1, 01 ;decrement delay counter JUMP NZ, rm_poll_240us ;repeat until zero TEST s2, 01 ;set carry flag if no pulse detected RETURN ; ; ;************************************************************************************** ; Read the DS_wire ;************************************************************************************** ; ; The DS_wire signal is read and returned in bit0 of register 's0'. ; Additionally the carry flag is set if the signal is High and reset if Low ; ; Registers used s0 ; read_DS_wire: INPUT s0, DS_wire_in_port AND s0, DS_wire ;ensure only bit0 is active TEST s0, DS_wire ;set carry flag if DS_wire is High RETURN ; ; ; ;************************************************************************************** ; Write a byte to DS2432 in regular speed mode. ;************************************************************************************** ; ; Bytes are written to the DS2432 with LSB first. ; ; The byte to be written should be provided in register 's3' and this will be preserved. ; ; Registers used s0,s1,s2,s3 ; write_byte_slow: LOAD s2, 08 ;8 bits to transmit wbs_loop: RR s3 ;test next bit LSB first JUMP C, wbs1 ;transmit '0' or '1' CALL write_Low_slow JUMP next_slow_bit wbs1: CALL write_High_slow next_slow_bit: SUB s2, 01 ;count bits JUMP NZ, wbs_loop ;repeat until 8-bits transmitted RETURN ; ; ; ;************************************************************************************** ; Write a '0' to DS_wire in regular speed mode. ;************************************************************************************** ; ; To write a '0' to the DS_wire the signal must be Low for 60 to 120us. This design ; generates a 78us active Low pulse. ; ; The DS2432 then requires at least 1us of recovery time for which this routine ; provides a 2us delay such that the entire write Low process (slot time) is 80us. ; A recovery time of 1us was also found to be marginal in practice probably due ; to the rise time of the DS_wire via the external pull up resistor. ; ; Registers used s0,s1 ; write_Low_slow: LOAD s0, 00 ;transmit Low pulse OUTPUT s0, DS_wire_out_port ;Delay of 78us is equivalent to 1950 instructions at 50MHz. ;This delay loop is formed of 27 instructions requiring 72 repetitions. LOAD s1, 48 ;72 (48 hex) wls_wait_78us: CALL delay_1us ;25 instructions including CALL SUB s1, 01 ;decrement delay counter JUMP NZ, wls_wait_78us ;repeat until zero LOAD s0, 01 ;end of Low pulse OUTPUT s0, DS_wire_out_port CALL delay_1us ;2us recovery time CALL delay_1us RETURN ; ; ;************************************************************************************** ; Write a '1' to DS_wire in regular speed mode. ;************************************************************************************** ; ; To write a '1' to the DS_wire the signal must be Low for 1 to 15us to instigate the ; write of the data. This design generates an 8us active Low pulse for this purpose. ; ; Then the output must be High for 53 to 114us to provide the '1' for the DS2432 to ; read and then provide recovery time. This design implements a 72us delay such that ; the entire write High process (slot time) is 80us ; ; Registers used s0,s1 ; write_High_slow: LOAD s0, 00 ;transmit Low pulse OUTPUT s0, DS_wire_out_port ;Delay of 8us is equivalent to 200 instructions at 50MHz. ;This delay loop is formed of 27 instructions requiring 8 repetitions. LOAD s1, 08 ;8 (08 hex) whs_wait_8us: CALL delay_1us ;25 instructions including CALL SUB s1, 01 ;decrement delay counter JUMP NZ, whs_wait_8us ;repeat until zero LOAD s0, 01 ;end of Low pulse OUTPUT s0, DS_wire_out_port ;Delay of 72us is equivalent to 1800 instructions at 50MHz. ;This delay loop is formed of 27 instructions requiring 67 repetitions. LOAD s1, 43 ;67 (43 hex) whs_wait_72us: CALL delay_1us ;25 instructions including CALL SUB s1, 01 ;decrement delay counter JUMP NZ, whs_wait_72us ;repeat until zero RETURN ; ; ; ;************************************************************************************** ; Read a byte from DS2432 in regular speed mode. ;************************************************************************************** ; ; Bytes are read from the DS2432 with LSB first. ; ; The byte read will be returned in register 's3'. ; ; Registers used s0,s1,s2,s3 ; read_byte_slow: LOAD s2, 08 ;8 bits to receive rbs_loop: CALL read_bit_slow ;read next bit LSB first SUB s2, 01 ;count bits JUMP NZ, rbs_loop ;repeat until 8-bits received RETURN ; ; ; ; ;************************************************************************************** ; Read a data bit sent from the DS2432 in regular speed mode. ;************************************************************************************** ; ; To read a bit, PicoBlaze must initiate the processed with an active Low pulse of ; 1 to 15us. This design generates a 4us active Low pulse for this purpose. ; ; Then DS2432 responds to the Low pulse by diving DS_wire in two different ways ; depending on the logic level it is trying to send back. ; ; For a logic '0' the DS2432 will drive the DS-wire Low for up to 15us after ; the start of the instigating pulse. Therefore PicoBlaze must read the DS-wire ; before this time has elapsed but only after it has itself released the wire. ; ; For a logic '1' the DS2432 will do nothing and hence the DS-wire will be pulled ; High by the external resistor after PicoBlaze has released the wire. PicoBlaze ; will sample the wire and detect the High level. ; ; In this design, PicoBlaze needs to detect the logic state of the wire after ; releasing the wire at 4us. Sampling the wire too quickly would not provide ; adequate time for a High signal to be formed by the pull up resistor. However, it ; must sample the wire before 15us have elapsed and any potential Low is removed. ; This design samples the wire at 12us which is 8us after the initiation pulse ends. ; ; A further delay of 68us is then allowed for the DS2432 to stop transmitting and ; to recover. This also mean that the entire read process (slot time) is 80us. ; ; The received data bit is SHIFTED into the MSB of register 's3'. In this way ; the reception of 8-bits will shift the first bit into the LSB position of 's3'. ; ; Registers used s0,s1,s3 ; read_bit_slow: LOAD s0, 00 ;transmit Low pulse OUTPUT s0, DS_wire_out_port ;Delay of 4us is equivalent to 100 instructions at 50MHz. ;This delay loop is formed of 27 instructions requiring 4 repetitions. LOAD s1, 04 ;4 (04 hex) rbs_wait_4us: CALL delay_1us ;25 instructions including CALL SUB s1, 01 ;decrement delay counter JUMP NZ, rbs_wait_4us ;repeat until zero LOAD s0, 01 ;end of Low pulse OUTPUT s0, DS_wire_out_port ;Delay of 8us is equivalent to 200 instructions at 50MHz. ;This delay loop is formed of 27 instructions requiring 8 repetitions. LOAD s1, 08 ;8 (08 hex) rbs_wait_8us: CALL delay_1us ;25 instructions including CALL SUB s1, 01 ;decrement delay counter JUMP NZ, rbs_wait_8us ;repeat until zero CALL read_DS_wire ;sample wire (carry = state) SRA s3 ;shift received bit into MSB of s3 ;Delay of 68us is equivalent to 1700 instructions at 50MHz. ;This delay loop is formed of 27 instructions requiring 63 repetitions. LOAD s1, 3F ;63 (3F hex) rbs_wait_68us: CALL delay_1us ;25 instructions including CALL SUB s1, 01 ;decrement delay counter JUMP NZ, rbs_wait_68us ;repeat until zero RETURN ; ; ;************************************************************************************** ; Software delay routines ;************************************************************************************** ; ; Delay of 1us. ; ; Constant value defines reflects the clock applied to KCPSM3. Every instruction ; executes in 2 clock cycles making the calculation highly predictable. The '6' in ; the following equation even allows for 'CALL delay_1us' instruction in the initiating code. ; ; delay_1us_constant = (clock_rate - 6)/4 Where 'clock_rate' is in MHz ; ; Register used s0 ; delay_1us: LOAD s0, delay_1us_constant wait_1us: SUB s0, 01 JUMP NZ, wait_1us RETURN ; ; Delay of 40us. ; ; Registers used s0, s1 ; delay_40us: LOAD s1, 28 ;40 x 1us = 40us wait_40us: CALL delay_1us SUB s1, 01 JUMP NZ, wait_40us RETURN ; ; ; Delay of 1ms. ; ; Registers used s0, s1, s2 ; delay_1ms: LOAD s2, 19 ;25 x 40us = 1ms wait_1ms: CALL delay_40us SUB s2, 01 JUMP NZ, wait_1ms RETURN ; ; Delay of 20ms. ; ; Registers used s0, s1, s2, s3 ; delay_20ms: LOAD s3, 14 ;20 x 1ms = 20ms wait_20ms: CALL delay_1ms SUB s3, 01 JUMP NZ, wait_20ms RETURN ; ; Delay of approximately 1 second. ; ; Registers used s0, s1, s2, s3, s4 ; delay_1s: LOAD s4, 14 ;50 x 20ms = 1000ms wait_1s: CALL delay_20ms SUB s4, 01 JUMP NZ, wait_1s RETURN ; ; ;************************************************************************************** ; UART communication routines ;************************************************************************************** ; ; Read one character from the UART ; ; Character read will be returned in a register called 'UART_data'. ; ; The routine first tests the receiver FIFO buffer to see if data is present. ; If the FIFO is empty, the routine waits until there is a character to read. ; As this could take any amount of time the wait loop could include a call to a ; subroutine which performs a useful function. ; ; ; Registers used s0 and UART_data ; read_from_UART: INPUT s0, status_port ;test Rx_FIFO buffer TEST s0, rx_data_present ;wait if empty JUMP NZ, read_character JUMP read_from_UART read_character: INPUT UART_data, UART_read_port ;read from FIFO RETURN ; ; ; ; Transmit one character to the UART ; ; Character supplied in register called 'UART_data'. ; ; The routine first tests the transmit FIFO buffer to see if it is full. ; If the FIFO is full, then the routine waits until it there is space. ; ; Registers used s0 ; send_to_UART: INPUT s0, status_port ;test Tx_FIFO buffer TEST s0, tx_full ;wait if full JUMP Z, UART_write JUMP send_to_UART UART_write: OUTPUT UART_data, UART_write_port RETURN ; ; ;************************************************************************************** ; Useful ASCII conversion and handling routines ;************************************************************************************** ; ; ; Convert character to upper case ; ; The character supplied in register s0. ; If the character is in the range 'a' to 'z', it is converted ; to the equivalent upper case character in the range 'A' to 'Z'. ; All other characters remain unchanged. ; ; Registers used s0. ; upper_case: COMPARE s0, 61 ;eliminate character codes below 'a' (61 hex) RETURN C COMPARE s0, 7B ;eliminate character codes above 'z' (7A hex) RETURN NC AND s0, DF ;mask bit5 to convert to upper case RETURN ; ; ; Convert hexadecimal value provided in register s0 into ASCII characters ; ; The value provided must can be any value in the range 00 to FF and will be converted into ; two ASCII characters. ; The upper nibble will be represented by an ASCII character returned in register s2. ; The lower nibble will be represented by an ASCII character returned in register s1. ; ; The ASCII representations of '0' to '9' are 30 to 39 hexadecimal which is simply 30 hex ; added to the actual decimal value. The ASCII representations of 'A' to 'F' are 41 to 46 ; hexadecimal requiring a further addition of 07 to the 30 already added. ; ; Registers used s0, s1 and s2. ; hex_byte_to_ASCII: LOAD s1, s0 ;remember value supplied SR0 s0 ;isolate upper nibble SR0 s0 SR0 s0 SR0 s0 CALL hex_to_ASCII ;convert LOAD s2, s0 ;upper nibble value in s2 LOAD s0, s1 ;restore complete value AND s0, 0F ;isolate lower nibble CALL hex_to_ASCII ;convert LOAD s1, s0 ;lower nibble value in s1 RETURN ; ; Convert hexadecimal value provided in register s0 into ASCII character ; ;Register used s0 ; hex_to_ASCII: SUB s0, 0A ;test if value is in range 0 to 9 JUMP C, number_char ADD s0, 07 ;ASCII char A to F in range 41 to 46 number_char: ADD s0, 3A ;ASCII char 0 to 9 in range 30 to 40 RETURN ; ; ; Send the two character HEX value of the register contents 's0' to the UART ; ; Registers used s0, s1, s2 ; send_hex_byte: CALL hex_byte_to_ASCII LOAD UART_data, s2 CALL send_to_UART LOAD UART_data, s1 CALL send_to_UART RETURN ; ; ; ; Convert the HEX ASCII characters contained in 's3' and 's2' into ; an equivalent hexadecimal value in register 's0'. ; The upper nibble is represented by an ASCII character in register s3. ; The lower nibble is represented by an ASCII character in register s2. ; ; Input characters must be in the range 00 to FF hexadecimal or the CARRY flag ; will be set on return. ; ; Registers used s0, s2 and s3. ; ASCII_byte_to_hex: LOAD s0, s3 ;Take upper nibble CALL ASCII_to_hex ;convert to value RETURN C ;reject if out of range LOAD s3, s0 ;remember value SL0 s3 ;multiply value by 16 to put in upper nibble SL0 s3 SL0 s3 SL0 s3 LOAD s0, s2 ;Take lower nibble CALL ASCII_to_hex ;convert to value RETURN C ;reject if out of range OR s0, s3 ;merge in the upper nibble with CARRY reset RETURN ; ; ; Routine to convert ASCII data in 's0' to an equivalent HEX value. ; ; If character is not valid for hex, then CARRY is set on return. ; ; Register used s0 ; ASCII_to_hex: ADD s0, B9 ;test for above ASCII code 46 ('F') RETURN C SUB s0, E9 ;normalise 0 to 9 with A-F in 11 to 16 hex RETURN C ;reject below ASCII code 30 ('0') SUB s0, 11 ;isolate A-F down to 00 to 05 hex JUMP NC, ASCII_letter ADD s0, 07 ;test for above ASCII code 46 ('F') RETURN C SUB s0, F6 ;convert to range 00 to 09 RETURN ASCII_letter: ADD s0, 0A ;convert to range 0A to 0F RETURN ; ; ; Read one character from UART and echo. ; Convert to upper case and return. ; ; read_upper_case: CALL read_from_UART ;read command character from UART CALL send_to_UART ;echo character LOAD s0, UART_data ;convert to upper case CALL upper_case RETURN ; ; ; Read two hex characters from UART and convert to single byte data ; obtain_8bits: CALL read_upper_case ;obtain one byte from UART LOAD s3, s0 CALL read_upper_case LOAD s2, s0 CALL ASCII_byte_to_hex RETURN ; ;************************************************************************************** ; Text messages ;************************************************************************************** ; ; ; Send Carriage Return to the UART ; send_CR: LOAD UART_data, character_CR CALL send_to_UART RETURN ; ; Send a space to the UART ; send_space: LOAD UART_data, character_space CALL send_to_UART RETURN ; ; ; Send a minus sign to the UART ; send_minus: LOAD UART_data, character_minus CALL send_to_UART RETURN ; ; ; Send the letter 't' to the UART ; send_t: LOAD UART_data, character_t CALL send_to_UART RETURN ; ; Send the letter 'e' to the UART ; send_e: LOAD UART_data, character_e CALL send_to_UART RETURN ; ; Send the letter 'a' to the UART ; send_a: LOAD UART_data, character_a CALL send_to_UART RETURN ; ; ; Send the letter 'd' to the UART ; send_d: LOAD UART_data, character_d CALL send_to_UART RETURN ; ; ; Send the letter 'r' to the UART ; send_r: LOAD UART_data, character_r CALL send_to_UART RETURN ; ; ; Send the letter 's' to the UART ; send_s: LOAD UART_data, character_s CALL send_to_UART RETURN ; ; ; Send the letter 'c' to the UART ; send_c: LOAD UART_data, character_c CALL send_to_UART RETURN ; ; ; Send 'PicoBlaze SHA-1 Algorithm v1.00' string to the UART ; send_welcome: CALL send_CR CALL send_CR LOAD UART_data, character_P CALL send_to_UART LOAD UART_data, character_i CALL send_to_UART CALL send_c LOAD UART_data, character_o CALL send_to_UART LOAD UART_data, character_B CALL send_to_UART LOAD UART_data, character_l CALL send_to_UART CALL send_a LOAD UART_data, character_z CALL send_to_UART CALL send_e CALL send_space LOAD UART_data, character_S CALL send_to_UART LOAD UART_data, character_H CALL send_to_UART LOAD UART_data, character_A CALL send_to_UART CALL send_minus LOAD UART_data, character_1 CALL send_to_UART CALL send_space LOAD UART_data, character_A CALL send_to_UART LOAD UART_data, character_l CALL send_to_UART LOAD UART_data, character_g CALL send_to_UART LOAD UART_data, character_o CALL send_to_UART CALL send_r LOAD UART_data, character_i CALL send_to_UART CALL send_t LOAD UART_data, character_h CALL send_to_UART LOAD UART_data, character_m CALL send_to_UART CALL send_space LOAD UART_data, character_v CALL send_to_UART LOAD UART_data, character_1 CALL send_to_UART LOAD UART_data, character_fullstop CALL send_to_UART LOAD UART_data, character_0 CALL send_to_UART LOAD UART_data, character_0 CALL send_to_UART CALL send_CR CALL send_CR RETURN ; ; ; ; ; ; ; Send DS2432 menu to the UART ; send_DS2432_menu: CALL send_CR CALL send_CR LOAD UART_data, character_1 CALL send_to_UART CALL send_minus CALL send_Write CALL send_space CALL send_scratchpad CALL send_CR LOAD UART_data, character_2 CALL send_to_UART CALL send_minus CALL send_Read CALL send_space CALL send_scratchpad CALL send_CR LOAD UART_data, character_3 CALL send_to_UART CALL send_minus LOAD UART_data, character_L CALL send_to_UART LOAD UART_data, character_o CALL send_to_UART CALL send_a CALL send_d CALL send_space LOAD UART_data, character_f CALL send_to_UART LOAD UART_data, character_i CALL send_to_UART CALL send_r CALL send_s CALL send_t CALL send_space CALL send_secret CALL send_CR LOAD UART_data, character_4 CALL send_to_UART CALL send_minus CALL send_Read CALL send_space LOAD UART_data, character_a CALL send_to_UART LOAD UART_data, character_u CALL send_to_UART CALL send_t LOAD UART_data, character_h CALL send_to_UART CALL send_space LOAD UART_data, character_P CALL send_to_UART CALL send_a LOAD UART_data, character_g CALL send_to_UART CALL send_e CALL send_CR RETURN ; ; ; ; Send carriage return, 'OK' and carriage return to the UART ; send_OK: CALL send_CR LOAD UART_data, character_O CALL send_to_UART LOAD UART_data, character_K CALL send_to_UART CALL send_CR RETURN ; ; ; Send 'scratchpad' to the UART ; send_scratchpad: CALL send_s CALL send_c CALL send_r CALL send_a CALL send_t CALL send_c LOAD UART_data, character_h CALL send_to_UART LOAD UART_data, character_p CALL send_to_UART CALL send_a CALL send_d RETURN ; ; ; Send 'secret' to the UART ; send_secret: CALL send_s CALL send_e CALL send_c CALL send_r CALL send_e CALL send_t RETURN ; ; ; Send 'Byte' to the UART ; send_Byte: LOAD UART_data, character_B CALL send_to_UART LOAD UART_data, character_y CALL send_to_UART CALL send_t CALL send_e RETURN ; ; ; Send 'Read' to the UART ; send_Read: LOAD UART_data, character_R CALL send_to_UART CALL send_e CALL send_a CALL send_d RETURN ; ; ; Send 'Write' to the UART ; send_Write: LOAD UART_data, character_W CALL send_to_UART CALL send_r LOAD UART_data, character_i CALL send_to_UART CALL send_t CALL send_e RETURN ; ; ; Send 'Pass' to the UART ; send_Pass: LOAD UART_data, character_P CALL send_to_UART CALL send_a CALL send_s CALL send_s CALL send_CR RETURN ; ; ; Send 'Fail' to the UART ; send_Fail: LOAD UART_data, character_F CALL send_to_UART CALL send_a LOAD UART_data, character_i CALL send_to_UART LOAD UART_data, character_l CALL send_to_UART CALL send_CR RETURN ; ; ; Send 'address=' to the UART ; send_address: CALL send_CR CALL send_a CALL send_d CALL send_d CALL send_r CALL send_e CALL send_s CALL send_s send_equals: LOAD UART_data, character_equals CALL send_to_UART RETURN ; ; ; Send 'data' to the UART ; send_data: CALL send_CR CALL send_d CALL send_a CALL send_t CALL send_a RETURN ; ; ; Send 'E/S=' to the UART ; send_ES: CALL send_CR LOAD UART_data, character_E CALL send_to_UART LOAD UART_data, character_divide CALL send_to_UART LOAD UART_data, character_S CALL send_to_UART JUMP send_equals ; ; ; Send 'code=' to the UART ; send_code: CALL send_c LOAD UART_data, character_o CALL send_to_UART CALL send_d CALL send_e JUMP send_equals ; ; ; Send 's/n=' to the UART ; send_sn: CALL send_s LOAD UART_data, character_divide CALL send_to_UART LOAD UART_data, character_n CALL send_to_UART JUMP send_equals ; ; ; Send 'crc=' to the UART ; send_crc: CALL send_c LOAD UART_data, character_r CALL send_to_UART CALL send_c JUMP send_equals ; ; ; ; Send 'mac=' to the UART ; send_mac: LOAD UART_data, character_m CALL send_to_UART CALL send_a CALL send_c JUMP send_equals ; ; ;************************************************************************************** ; Interrupt Service Routine (ISR) ;************************************************************************************** ; ; Interrupts are not used in this design. This is a place keeper only. ; ADDRESS 3FE ISR: RETURNI ENABLE ; ; ;************************************************************************************** ; Interrupt Vector ;************************************************************************************** ; ADDRESS 3FF JUMP ISR ; ;