mirror of
https://github.com/pConst/basic_verilog.git
synced 2025-01-28 07:02:55 +08:00
2176 lines
124 KiB
Plaintext
2176 lines
124 KiB
Plaintext
; KCPSM3 Program - Security control and design authentication.
|
|
;
|
|
; This program is provided for use with the reference design
|
|
; 'low_cost_design_authentication_for_spartan_3e.vhd' implemented on the Spartan-3E Starter
|
|
; Kit. The program provides design authentication control over the 'real' application as well
|
|
; as providing features to enable evaluation of the design authentication method.
|
|
;
|
|
; Ken Chapman - Xilinx Ltd
|
|
;
|
|
; Version v1.00 - 1st November 2006
|
|
;
|
|
; This code communicates with the StrataFLASH memory to implement a design authentication
|
|
; algorithm which then enables the main application design in various ways. To facilitate
|
|
; evaluation of design authentication this design also interacts with the LCD display
|
|
; and PC (via UART based RS232 link) to indicate authentication status and allow control
|
|
; over the authentication validity of the design. Therefore this program includes:-
|
|
;
|
|
; 1) Code required to check authorisation which would be included in a production design.
|
|
; 2) Code required to program the authentication value into FLASH memory which would
|
|
; typically only be implemented in a special design used at a secure programming
|
|
; facility as part of the production programming procedure.
|
|
; 3) Code to allow you to see what is happening at all stages which is code that should
|
|
; never be included in a real production design as it reveals secrets that should remain
|
|
; hidden in order to make the task of breaking the security as difficult as possible.
|
|
;
|
|
; IMPORTANT - Feel free to use this code as a reference for your own security scheme but
|
|
; never use this code unmodified.
|
|
;
|
|
;
|
|
;**************************************************************************************
|
|
; NOTICE:
|
|
;
|
|
; Copyright Xilinx, Inc. 2006. This code may be contain portions patented by other
|
|
; third parties. By providing this core as one possible implementation of a standard,
|
|
; Xilinx is making no representation that the provided implementation of this standard
|
|
; is free from any claims of infringement by any third party. Xilinx expressly
|
|
; disclaims any warranty with respect to the adequacy of the implementation, including
|
|
; but not limited to any warranty or representation that the implementation is free
|
|
; from claims of any third party. Furthermore, Xilinx is providing this core as a
|
|
; courtesy to you and suggests that you contact all third parties to obtain the
|
|
; necessary rights to use this implementation.
|
|
;
|
|
;
|
|
;**************************************************************************************
|
|
; Port definitions
|
|
;**************************************************************************************
|
|
;
|
|
;
|
|
; UART ports
|
|
;
|
|
; Connection to PC to allow display of progress information and to operate simple
|
|
; menu of commands.
|
|
;
|
|
CONSTANT status_port, 00 ;UART and memory status
|
|
CONSTANT tx_half_full, 01 ; Transmitter half full - bit0
|
|
CONSTANT tx_full, 02 ; FIFO tx_full - bit1
|
|
CONSTANT rx_data_present, 04 ; Receiver data present - bit2
|
|
CONSTANT rx_half_full, 08 ; FIFO half full - bit3
|
|
CONSTANT rx_full, 10 ; rx_full - bit4
|
|
CONSTANT spare1, 20 ; spare '0' - bit5
|
|
CONSTANT spare2, 40 ; spare '0' - bit6
|
|
CONSTANT strataflash_sts, 80 ; StrataFLASH STS - bit7
|
|
;
|
|
CONSTANT UART_read_port, 01 ;UART Rx data input
|
|
;
|
|
CONSTANT UART_write_port, 08 ;UART Tx data output
|
|
;
|
|
;
|
|
; LCD Display
|
|
;
|
|
;The master enable signal is not used by the LCD display itself
|
|
;but is used to prevent any contention with the StrataFLASH memory that
|
|
;is connected to the same data pins. In this design the StrataFLASH memory is
|
|
;used in 8-bit mode so not contention should exist but this master enable
|
|
;facilty is then available for anyone wanting to modify the design for use
|
|
;with a 16-bit interface.
|
|
;
|
|
CONSTANT LCD_output_port, 20 ;LCD character module output data and control
|
|
CONSTANT LCD_E, 01 ; active High Enable E - bit0
|
|
CONSTANT LCD_RW, 02 ; Read=1 Write=0 RW - bit1
|
|
CONSTANT LCD_RS, 04 ; Instruction=0 Data=1 RS - bit2
|
|
CONSTANT LCD_drive, 08 ; Master enable (active High) - bit3
|
|
CONSTANT LCD_DB4, 10 ; 4-bit Data DB4 - bit4
|
|
CONSTANT LCD_DB5, 20 ; interface Data DB5 - bit5
|
|
CONSTANT LCD_DB6, 40 ; Data DB6 - bit6
|
|
CONSTANT LCD_DB7, 80 ; Data DB7 - bit7
|
|
;
|
|
;
|
|
CONSTANT LCD_input_port, 03 ;LCD character module input data
|
|
CONSTANT LCD_read_spare0, 01 ; Spare bits - bit0
|
|
CONSTANT LCD_read_spare1, 02 ; are zero - bit1
|
|
CONSTANT LCD_read_spare2, 04 ; - bit2
|
|
CONSTANT LCD_read_spare3, 08 ; - bit3
|
|
CONSTANT LCD_read_DB4, 10 ; 4-bit Data DB4 - bit4
|
|
CONSTANT LCD_read_DB5, 20 ; interface Data DB5 - bit5
|
|
CONSTANT LCD_read_DB6, 40 ; Data DB6 - bit6
|
|
CONSTANT LCD_read_DB7, 80 ; Data DB7 - bit7
|
|
;
|
|
;
|
|
;
|
|
; StrataFLASH memory ports
|
|
;
|
|
; The FLASH memory is used to hold the authentication value as well as provide the
|
|
; unique serial number from which the authentication algorithm computes the value.
|
|
; In practice, the FLASH will also hold the configuration image for the Spartan device.
|
|
;
|
|
;
|
|
CONSTANT SF_data_in_port, 02 ;Read data from StrataFLASH device
|
|
;
|
|
CONSTANT SF_data_out_port, 80 ;Data to write into StrataFLASH device
|
|
;
|
|
CONSTANT SF_addr_hi_port, 83 ;StrataFLASH address[21:16] (6 LSB's)
|
|
CONSTANT SF_addr_mi_port, 82 ;StrataFLASH address[15:8]
|
|
CONSTANT SF_addr_lo_port, 81 ;StrataFLASH address[7:0]
|
|
;
|
|
CONSTANT SF_control_port, 40 ;StrataFLASH control
|
|
CONSTANT SF_read, 01 ; active High read - bit0
|
|
CONSTANT SF_ce, 02 ; active Low device enable - bit1
|
|
CONSTANT SF_we, 04 ; active Low write - bit2
|
|
;
|
|
;
|
|
; Design Authentication enable/disable signals.
|
|
;
|
|
; Hardware controls over the 'real' application.
|
|
;
|
|
CONSTANT authentication_control_port, 10 ;Design disable control port
|
|
CONSTANT security_disable_interrupts, 01 ; active High disable of interrupt generation - bit0
|
|
CONSTANT security_disable_outputs, 02 ; active High disable of output pins - bit1
|
|
;
|
|
; Pseudo Random number generator
|
|
;
|
|
CONSTANT random_value_port, 04 ;read LFSR counter value
|
|
;
|
|
;
|
|
; Link FIFO buffer
|
|
;
|
|
; Provides a connection to the 'real' application such that 'soft tokens' in the
|
|
; form of short messages to be passed to the 'real' application to enable or disable
|
|
; it depending on the authentication status.
|
|
;
|
|
CONSTANT link_FIFO_write_port, 04 ;write data to FIFO
|
|
;
|
|
;
|
|
;**************************************************************************************
|
|
; Special Register usage
|
|
;**************************************************************************************
|
|
;
|
|
NAMEREG sF, UART_data ;used to pass data to and from the UART
|
|
;
|
|
;
|
|
;
|
|
;**************************************************************************************
|
|
;Scratch Pad Memory Locations
|
|
;**************************************************************************************
|
|
;
|
|
CONSTANT ISR_preserve_s0, 00 ;preserve register contents during Interrupt Service Routine
|
|
;
|
|
;
|
|
CONSTANT serial_number0, 10 ;64-bit serial number of StrataFlash
|
|
CONSTANT serial_number1, 11 ;LS-Byte first
|
|
CONSTANT serial_number2, 12
|
|
CONSTANT serial_number3, 13
|
|
CONSTANT serial_number4, 14
|
|
CONSTANT serial_number5, 15
|
|
CONSTANT serial_number6, 16
|
|
CONSTANT serial_number7, 17
|
|
;
|
|
;
|
|
CONSTANT computed_CRC0, 18 ;computed 16-bit CRC based on the
|
|
CONSTANT computed_CRC1, 19 ; StrataFlash unique serial number (LS-Byte first)
|
|
;
|
|
;
|
|
CONSTANT authentication_CRC0, 1A ;16-bit CRC value read from authentication
|
|
CONSTANT authentication_CRC1, 1B ; area of StrataFLASH memory (LS-Byte first)
|
|
;
|
|
;
|
|
CONSTANT authentication_status, 1C ;Status of design authentication
|
|
;
|
|
;
|
|
;**************************************************************************************
|
|
;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_divide, 2F ;'/'
|
|
CONSTANT character_plus, 2B
|
|
CONSTANT character_comma, 2C
|
|
CONSTANT character_less_than, 3C
|
|
CONSTANT character_greater_than, 3E
|
|
CONSTANT character_equals, 3D
|
|
CONSTANT character_space, 20
|
|
CONSTANT character_CR, 0D ;carriage return
|
|
CONSTANT character_question, 3F ;'?'
|
|
CONSTANT character_dollar, 24
|
|
CONSTANT character_exclaim, 21 ;'!'
|
|
CONSTANT character_BS, 08 ;Back Space command character
|
|
;
|
|
;
|
|
;
|
|
;
|
|
;
|
|
;**************************************************************************************
|
|
;Initialise the system
|
|
;**************************************************************************************
|
|
;
|
|
cold_start: CALL SF_init ;initialise StrataFLASH controls
|
|
LOAD s0, 00 ;Start with application enabled in hardware
|
|
OUTPUT s0, authentication_control_port
|
|
LOAD s0, character_P ;start with design enabled by software (see ISR)
|
|
STORE s0, authentication_status
|
|
CALL delay_1s ;delay to allow system to settle
|
|
CALL LCD_reset ;Initialise the LCD
|
|
;
|
|
ENABLE INTERRUPT ;interrupts to provide software enable to application
|
|
;
|
|
;**************************************************************************************
|
|
; Main program
|
|
;**************************************************************************************
|
|
;
|
|
; The main program follows a logical sequence of events describing the power on and
|
|
; authentication process of a design. This process will is either successfully authorises
|
|
; the 'real' application to operate or fail to authenticate and disable the 'real'
|
|
; application in a similar way to a production design. The only difference that it keeps
|
|
; you informed about what it is doing on both the LCD display and PC terminal via the UART.
|
|
; A real production design should keep all details hidden.
|
|
;
|
|
; Following the authentication check and control over the 'real' application a simple menu
|
|
; is provided on the PC terminal to allow you to read, write and erase the authentication
|
|
; area of the StrataFLASH memory and therefore evaluate the design authentication security
|
|
; of this reference design.
|
|
;
|
|
;
|
|
;
|
|
; Write welcome message to LCD display
|
|
;
|
|
warm_start: LOAD s5, 12 ;Line 1 position 2
|
|
CALL LCD_cursor
|
|
CALL disp_PicoBlaze ;Display 'PicoBlaze'
|
|
LOAD s5, 25 ;Line 2 position 5
|
|
CALL LCD_cursor
|
|
CALL disp_Security ;Display 'Security'
|
|
;
|
|
; Write welcome message to PC via UART
|
|
;
|
|
CALL send_welcome
|
|
;
|
|
;
|
|
; Display 'Copyright Ken Chapman 2006' via the UART.
|
|
;
|
|
; This message is significant because it demonstrates that the design now has a 'watermark'.
|
|
; The ASCII codes for this string are part of the PicoBlaze program stored in a Block
|
|
; Memory and therefore are also part of the configuration bit stream. If someone tries to
|
|
; change or delete this copyright message the hardware design will detect the change to the
|
|
; Block memory contents and also inhibit the design.
|
|
;
|
|
CALL send_Copyright
|
|
;
|
|
;
|
|
;
|
|
; Delay of 10 seconds before performing any security checks.
|
|
;
|
|
; This allows the design to work for a short time which could be important for
|
|
; production testing.
|
|
;
|
|
; Having a significant time delay (days or weeks) before security checks means that someone
|
|
; attempting to clone the product may not be aware that there is any form of design security
|
|
; at all until products are in the field are failing. A time delay also impedes the ability to
|
|
; attempt to break the security and confirm if an attempt is or is not successful.
|
|
;
|
|
LOAD s5, 0A ;delay of 10 seconds.
|
|
CALL delay_Ns
|
|
;
|
|
;
|
|
;
|
|
; Read serial number of the StrataFLASH memory.
|
|
; The whole principle of low cost design security is based on this unique number. Clearly this
|
|
; number is not a secret, but what we then go on to do with it should normally be kept secret.
|
|
;
|
|
CALL read_SF_serial_number ;read serial number from FLASH memory
|
|
CALL send_serial_number ;send value to UART for display on PC
|
|
CALL disp_serial_number ;display serial number on LCD display.
|
|
CALL send_CR
|
|
;
|
|
;
|
|
;
|
|
LOAD s5, 0A ;delay of 10 seconds to read messages.
|
|
CALL delay_Ns
|
|
;
|
|
;
|
|
;
|
|
; Compute the 16-bit CRC for the serial number as an authentication value for the design.
|
|
; The CRC value is formed in register pair [sE,sD]. To complicate the authentication value
|
|
; the initial contents of the registers are seeded with a 'secret' number.
|
|
; Hint 1 - The CRC computation could be implemented in hardware where it is less visible.
|
|
; Hint 2 - There are more secure algorithms such as SHA-1 which could be used to generate
|
|
; authentication values that are extremely difficult to decode.
|
|
;
|
|
;
|
|
LOAD sE, 15 ;seed CRC register with an initial value provided by my daughter when asked :-)
|
|
LOAD sD, 8E
|
|
CALL compute_seeded_CRC ;compute CRC for serial number and configuration memory
|
|
;
|
|
; Store CRC value in scratch pad memory and display computed CRC value on the PC via UART.
|
|
;
|
|
STORE sD, computed_CRC0 ;store CRC value
|
|
STORE sE, computed_CRC1
|
|
CALL send_Computed_CRC ;display computed CRC value on PC via UART
|
|
LOAD s0, sE
|
|
CALL send_hex_byte
|
|
LOAD s0, sD
|
|
CALL send_hex_byte
|
|
CALL send_CR
|
|
;
|
|
;
|
|
;
|
|
; Read the authenticated CRC value stored in StrataFLASH memory.
|
|
; 16-bit value is hidden in 256 bytes of random numbers to make it more difficult
|
|
; for an attacker to identify.
|
|
; Read value is stored in scratch pad memory and displayed on the PC via UART.
|
|
;
|
|
CALL read_authentication ;read StrataFLASH memory into [sB,sA]
|
|
STORE sA, authentication_CRC0 ;store CRC value
|
|
STORE sB, authentication_CRC1
|
|
CALL send_FLASH_CRC ;display CRC value from FLASH on PC via UART
|
|
LOAD s0, sB
|
|
CALL send_hex_byte
|
|
LOAD s0, sA
|
|
CALL send_hex_byte
|
|
CALL send_CR
|
|
;
|
|
;
|
|
; Compare the computed CRC value with the authentication value stored in StrataFLASH
|
|
; and determine if the design is authenticated. Then decide course of action.
|
|
;
|
|
CALL LCD_clear ;clear LCD display
|
|
CALL disp_Authentication ;prepare LCD display for result of authentication
|
|
CALL send_Authentication ;prepare PC display for result of authentication
|
|
;
|
|
COMPARE sA, sD ;Perform comparison of CRC values
|
|
JUMP NZ, auth_failure
|
|
COMPARE sB, sE
|
|
JUMP NZ, auth_failure
|
|
;
|
|
;
|
|
; Authentication Successful Process
|
|
;
|
|
; In this mode the design continues to operate and for evaluation
|
|
; purposes this design transfers control to the simple menu immediately.
|
|
;
|
|
auth_passed: CALL disp_Passed ;display successful authentication on LCD display
|
|
CALL send_PASSED ;display successful authentication on PC via UART
|
|
JUMP Menu
|
|
;
|
|
; Authentication Failure Process
|
|
;
|
|
; When the authentication fails two hardware based disable methods are demonstrated. Then
|
|
; the failed status is remembered for future software token messages to demonstrate software
|
|
; based disabling of the 'real' application. Finally the simple menu of options is presented
|
|
; to allow evaluation to continue.
|
|
;
|
|
;
|
|
auth_failure: CALL disp_Failed ;display failure to authenticate on LCD display
|
|
CALL send_FAILED ;display failure to authenticate on PC via UART
|
|
CALL send_CR
|
|
CALL disable_app_hardware ;sequence hardware disable signals
|
|
LOAD s0, character_F ;change authentication status to 'F' for failed.
|
|
STORE s0, authentication_status ; so that application software disable is demonstrated
|
|
;
|
|
;
|
|
;
|
|
; Menu of options for authentication processing
|
|
;
|
|
Menu: CALL send_Menu ;display menu and prompt
|
|
CALL read_from_UART ;read character from PC
|
|
CALL upper_case ;convert to upper case
|
|
COMPARE UART_data, character_R
|
|
JUMP Z, read_command
|
|
COMPARE UART_data, character_E
|
|
JUMP Z, erase_command
|
|
COMPARE UART_data, character_A
|
|
JUMP Z, authorise_command
|
|
JUMP Menu ;repeat menu for invalid selection
|
|
;
|
|
;
|
|
;
|
|
read_command: CALL send_CR
|
|
CALL send_auth_page
|
|
CALL send_CR
|
|
CALL send_CR
|
|
JUMP Menu
|
|
;
|
|
;
|
|
;
|
|
erase_command: CALL send_Erase_in_progress
|
|
CALL erase_authentication
|
|
CALL send_OK
|
|
JUMP Menu
|
|
;
|
|
;
|
|
;
|
|
authorise_command: CALL send_Writing ;Send 'Writing Authorisation' message
|
|
CALL send_CR
|
|
FETCH sD, computed_CRC0 ;fetch computed CRC value
|
|
FETCH sE, computed_CRC1
|
|
CALL write_authentication ;write computed CRC to FLASH with random data
|
|
CALL send_OK
|
|
JUMP Menu
|
|
;
|
|
;
|
|
;**************************************************************************************
|
|
; Drive failure signals to the application.
|
|
;**************************************************************************************
|
|
;
|
|
; When the design fails to authorise, these controls cause the application to behave in
|
|
; a strange way!
|
|
;
|
|
;
|
|
; Disable interrupts to application PicoBlaze to stop PWM generation completely for 5 seconds
|
|
;
|
|
disable_app_hardware: LOAD s0, security_disable_interrupts
|
|
OUTPUT s0, authentication_control_port
|
|
LOAD s5, 05
|
|
CALL delay_Ns
|
|
;
|
|
; Enable application for 5 seconds
|
|
;
|
|
LOAD s0, 00
|
|
OUTPUT s0, authentication_control_port
|
|
LOAD s5, 05
|
|
CALL delay_Ns
|
|
;
|
|
; Disable and/or scramble outputs connected to application PicoBlaze for 5 seconds
|
|
;
|
|
LOAD s0, security_disable_outputs
|
|
OUTPUT s0, authentication_control_port
|
|
LOAD s5, 05
|
|
CALL delay_Ns
|
|
;
|
|
;
|
|
; Enable application in hardware so that software disable function can then be
|
|
; demonstrated until the design is reconfigured and authentication test repeated.
|
|
;
|
|
LOAD s0, 00
|
|
OUTPUT s0, authentication_control_port
|
|
RETURN
|
|
;
|
|
;
|
|
;
|
|
;**************************************************************************************
|
|
; Send the 64-bit serial number stored in scratch pad memory to the UART
|
|
;**************************************************************************************
|
|
;
|
|
; The serial number should previously have been copied into the 8 ascending scratch pad
|
|
; memory locations called 'serial_number0' through to 'serial_number7'.
|
|
;
|
|
; The serial number is displayed MS-Byte first.
|
|
;
|
|
; Registers used s0,s1,s2,s3
|
|
;
|
|
send_serial_number: CALL send_FLASH_Serial_Number ;display text message
|
|
LOAD s3, serial_number7 ;pointer to scratch pad memory
|
|
send_SN_loop: FETCH s0, (s3) ;read serial number byte
|
|
CALL send_hex_byte ;display byte
|
|
CALL send_space ;display byte
|
|
COMPARE s3, serial_number0 ;check for 8 bytes sent to UART
|
|
JUMP Z, end_send_SN
|
|
SUB s3, 01 ;increment memory pointer
|
|
JUMP send_SN_loop
|
|
;
|
|
end_send_SN: CALL send_CR
|
|
RETURN
|
|
;
|
|
;
|
|
;
|
|
;**************************************************************************************
|
|
; Display the 64-bit serial number stored in scratch pad memory on the LCD display
|
|
;**************************************************************************************
|
|
;
|
|
; The serial number should previously have been copied into the 8 ascending scratch pad
|
|
; memory locations called 'serial_number0' through to 'serial_number7'.
|
|
;
|
|
; The serial number is displayed MS-Byte first.
|
|
;
|
|
; Registers used s0,s1,s2,s3,s4,s5,s6
|
|
;
|
|
disp_serial_number: CALL LCD_clear ;clear LCD display
|
|
LOAD s5, 10 ;Line 1 position 0
|
|
CALL LCD_cursor
|
|
CALL disp_FLASH_Serial_No ;display text message
|
|
LOAD s5, 20 ;Line 2 position 0
|
|
CALL LCD_cursor
|
|
LOAD s6, serial_number7 ;pointer to scratch pad memory
|
|
disp_SN_loop: FETCH s0, (s6) ;read serial number byte
|
|
CALL disp_hex_byte ;display byte
|
|
COMPARE s6, serial_number0 ;check for 8 bytes sent to UART
|
|
JUMP Z, end_disp_SN
|
|
SUB s6, 01 ;increment memory pointer
|
|
JUMP disp_SN_loop
|
|
;
|
|
end_disp_SN: CALL send_CR
|
|
RETURN
|
|
;
|
|
;
|
|
;**************************************************************************************
|
|
; Compute a 16-bit CRC value for the StrataFLASH 64-bit serial number.
|
|
;**************************************************************************************
|
|
;
|
|
; This routing performs a 16-bit CRC calculation for the 64-bit unique serial number
|
|
; of the StrataFLASH memory which forms the authentication value for the design.
|
|
;
|
|
; The 16-bit CRC value returned in register pair [sE,sD] will be reflective of the unique
|
|
; serial number. This will be used as the authentication value for the design which is
|
|
; stored at known locations in the FLASH memory.
|
|
;
|
|
; A direct copy of the FLASH contents will not authorise a design to operate because the
|
|
; authentication value will not match the CRC value generated from the different serial number.
|
|
;
|
|
; To complicate the CRC value generation the CRC register can be seeded with a value rather
|
|
; than starting with a clear register.
|
|
;
|
|
;
|
|
; Registers used s0,s1,s2,s3
|
|
;
|
|
compute_seeded_CRC: LOAD s4, serial_number0 ;pointer to scratch pad memory holding serial number
|
|
CRC_send_loop: FETCH s3, (s4) ;read serial number byte
|
|
CALL compute_CRC16 ;compute CRC for value in 's3'
|
|
COMPARE s4, serial_number7 ;check for 8 bytes processed
|
|
RETURN Z
|
|
ADD s4, 01 ;increment memory pointer
|
|
JUMP CRC_send_loop
|
|
;
|
|
;
|
|
;**************************************************************************************
|
|
; Compute 16-bit CRC using the polynomial X16 + X15 + X2 + 1.
|
|
;**************************************************************************************
|
|
;
|
|
;
|
|
; This routine computes a 16-bit CRC in the register pair [sE,sD] and these
|
|
; registers must not be disturbed between calls of this routine.
|
|
;
|
|
; 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.
|
|
;
|
|
; Before starting a CRC computation either clear or pre-load (seed) the register pair
|
|
; [sE,sD] and do not disturb the value of the register pair between calling this routine.
|
|
;
|
|
; Registers used s0,s1,s3,sD,sE
|
|
; s3 is preserved.
|
|
; sD and sE should not be disturbed between calls if CRC value is required.
|
|
;
|
|
;
|
|
;
|
|
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 256 bytes of StrataFLASH memory including the authentication value.
|
|
;**************************************************************************************
|
|
;
|
|
; This routine reads the authentication value from the StrataFLASH memory. In this
|
|
; design the authentication value is only 2 bytes which once read will be returned
|
|
; in the register pair [sB,sA].
|
|
;
|
|
; To make the authentication value more difficult to identify, it is hidden in 256 bytes
|
|
; of pseudo random values which will also appear different in each FLASH device inspected.
|
|
; This routine deliberately reads all 256 bytes that are stored and abstracts the required
|
|
; 2 bytes of information from them otherwise it would be easy to observe which addresses
|
|
; of the block were being accessed.
|
|
;
|
|
; Another way that an attacker may deduce which address locations are important would be to
|
|
; observe the time between read accesses and note when there is any difference. In this case
|
|
; the attacker is attempting to detect when PicoBlaze takes slightly longer to execute the
|
|
; instructions which store the important bytes in scratch pad memory. So to avoid this
|
|
; detection this routine inserts an additional random delay between reads to mask any code
|
|
; execution differences.
|
|
;
|
|
; The 256 bytes are stored at addresses 060000 to 0600FF hex (the first block above the
|
|
; XC3S500E configuration image which occupies 000000 to 04547F hex). The 2 bytes forming the
|
|
; actual authentication value are stored as 4-bit nibbles in 4 different locations in this range.
|
|
;
|
|
;
|
|
; High Order Nibble Low Order Nibble
|
|
; (NNNNxxxx) (xxxxNNNN)
|
|
;
|
|
; LS-Byte in 'sA' Addr=060010 Addr=06007F
|
|
; MS-Byte in 'sB' Addr=060025 Addr=0600FA
|
|
;
|
|
;
|
|
read_authentication: LOAD s9, 06 ;start address in FLASH
|
|
LOAD s8, 00
|
|
LOAD s7, 00
|
|
auth_read_loop: CALL SF_byte_read ;read byte from FLASH into s0
|
|
COMPARE s7, 10 ;check for bytes/nibbles that contain real information
|
|
JUMP NZ, auth_check2
|
|
LOAD sA, s0 ;isolate upper order nibble for LS-Byte
|
|
AND sA, F0
|
|
auth_check2: COMPARE s7, 25
|
|
JUMP NZ, auth_check3
|
|
LOAD sB, s0 ;isolate upper order nibble for MS-Byte
|
|
AND sB, F0
|
|
auth_check3: COMPARE s7, 7F
|
|
JUMP NZ, auth_check4
|
|
AND s0, 0F ;isolate lower order nibble for LS-Byte
|
|
OR sA, s0 ; and merge with upper order nibble
|
|
auth_check4: COMPARE s7, FA
|
|
JUMP NZ, next_auth_read
|
|
AND s0, 0F ;isolate lower order nibble for MS-Byte
|
|
OR sB, s0 ; and merge with upper order nibble
|
|
next_auth_read: ADD s7, 01 ;increment address
|
|
RETURN Z ;complete after 256 reads
|
|
INPUT s0, random_value_port ;random delay between reads
|
|
auth_read_delay: SUB s0, 01
|
|
JUMP NZ, auth_read_delay
|
|
JUMP auth_read_loop
|
|
;
|
|
;
|
|
;**************************************************************************************
|
|
; Read 256 bytes (page) of StrataFLASH memory containing the authentication value.
|
|
;**************************************************************************************
|
|
;
|
|
; This routine reads the StrataFLASH memory and displays the contents on the PC display
|
|
; via the UART. The display will be 256 bytes from address range 060000 to 0600FF displayed
|
|
; as 16 lines of 16 bytes with each line commencing with the address of the first byte.
|
|
;
|
|
send_auth_page: LOAD s9, 06 ;start address in FLASH
|
|
LOAD s8, 00
|
|
LOAD s7, 00
|
|
auth_line_loop: CALL send_CR
|
|
CALL send_hex_3bytes ;display address
|
|
CALL send_space
|
|
auth_byte_loop: CALL send_space
|
|
CALL SF_byte_read ;read byte into s0
|
|
CALL send_hex_byte ;display byte
|
|
ADD s7, 01 ;increment FLASH address
|
|
TEST s7, 0F ;test for 16 byte boundary
|
|
JUMP NZ, auth_byte_loop
|
|
TEST s7, FF ;test for roll over of 256 bytes
|
|
JUMP NZ, auth_line_loop
|
|
CALL send_CR
|
|
RETURN
|
|
;
|
|
;
|
|
;
|
|
;
|
|
;**************************************************************************************
|
|
; Write 256 bytes of StrataFLASH memory including the authentication value.
|
|
;**************************************************************************************
|
|
;
|
|
; This routine writes the authentication value to the StrataFLASH memory. This routine
|
|
; would normally be part of a production programming mechanism and not part of the
|
|
; final design which only reads and confirms authentication. This routine does not
|
|
; require and special measures to confuse an attacker if it is only used in a secure
|
|
; production environment.
|
|
;
|
|
; The 2 bytes forming the actual authentication value are stored as 4-bit nibbles in
|
|
; 4 different locations in the address range 600000 to 6000FF hex (256 bytes) with
|
|
; all remaining locations filled with pseudo random values.
|
|
;
|
|
; The authentication value to be stored in StrataFLASH memory should be provided in
|
|
; the register pair [sE,sD] and will be stored in the following locations.
|
|
;
|
|
; High Order Nibble Low Order Nibble
|
|
; (NNNNxxxx) (xxxxNNNN)
|
|
;
|
|
; LS-Byte in 'sD' Addr=060010 Addr=06007F
|
|
; MS-Byte in 'sE' Addr=060025 Addr=0600FA
|
|
;
|
|
;
|
|
write_authentication: LOAD s9, 06 ;start address in FLASH
|
|
LOAD s8, 00
|
|
LOAD s7, 00
|
|
auth_write_loop: INPUT s0, random_value_port ;Obtain random value
|
|
COMPARE s7, 10 ;check for bytes/nibbles that need to be real information
|
|
JUMP NZ, auth_write_check2
|
|
LOAD s1, sD ;merge upper order nibble for LS-Byte with random
|
|
AND s1, F0
|
|
AND s0, 0F
|
|
OR s0, s1
|
|
auth_write_check2: COMPARE s7, 25
|
|
JUMP NZ, auth_write_check3
|
|
LOAD s1, sE ;merge upper order nibble for MS-Byte with random
|
|
AND s1, F0
|
|
AND s0, 0F
|
|
OR s0, s1
|
|
auth_write_check3: COMPARE s7, 7F
|
|
JUMP NZ, auth_write_check4
|
|
LOAD s1, sD ;merge lower order nibble for LS-Byte with random
|
|
AND s1, 0F
|
|
AND s0, F0
|
|
OR s0, s1
|
|
auth_write_check4: COMPARE s7, FA
|
|
JUMP NZ, write_auth
|
|
LOAD s1, sE ;merge lower order nibble for MS-Byte with random
|
|
AND s1, 0F
|
|
AND s0, F0
|
|
OR s0, s1
|
|
write_auth: CALL SF_single_byte_write ;write byte to FLASH
|
|
ADD s7, 01 ;increment address
|
|
RETURN Z ;complete after 256 writes
|
|
JUMP auth_write_loop
|
|
;
|
|
;
|
|
;**************************************************************************************
|
|
; Erase authentication value from StrataFLASH memory.
|
|
;**************************************************************************************
|
|
;
|
|
; Erase block 3 of the StrataFLASH memory which covers the address range 060000 to 07FFFF.
|
|
; This erases the area containing the authentication value and random values which helps
|
|
; to hide it.
|
|
;
|
|
erase_authentication: LOAD s9, 06 ;set address to 06xxxx hex which defines block 3 (060000 to 07FFFF)
|
|
CALL SF_erase_block
|
|
RETURN
|
|
;
|
|
;
|
|
;**************************************************************************************
|
|
; Initialise the StrataFlash Memory control signals.
|
|
;**************************************************************************************
|
|
;
|
|
; SF_read = 0 - Output enable off
|
|
; SF_ce = 1 - Deselect StrataFLASH memory
|
|
; SF_we = 1 - Write enable off
|
|
;
|
|
; Register used s0
|
|
;
|
|
SF_init: LOAD s0, 06
|
|
OUTPUT s0, SF_control_port
|
|
RETURN
|
|
;
|
|
;
|
|
;
|
|
;**************************************************************************************
|
|
; StrataFLASH Block Erase
|
|
;**************************************************************************************
|
|
;
|
|
; This routine will erase one 128k-byte block of the StrataFLASH memory.
|
|
; The block to be erased is specified by the contents of register 's9'.
|
|
;
|
|
; s9=06 erases Block 3 (address range 060000 to 07FFFF)
|
|
;
|
|
;
|
|
; To erase a block the 24-bit address must be set and then the block erase command
|
|
; (20 hex) written to the memory followed by the write confirm command (D0 hex).
|
|
;
|
|
; The act of erasing a block may take up to 1 second to complete. This routine
|
|
; waits for the memory to be ready before restoring the normal read array mode and
|
|
; returning.
|
|
;
|
|
; Registers used s0,s1,s7,s8,s9
|
|
;
|
|
SF_erase_block: LOAD s8, 00 ;define lower address of block = xx0000
|
|
LOAD s7, 00
|
|
LOAD s1, 20 ;block erase command
|
|
CALL SF_byte_write
|
|
LOAD s1, D0 ;write confirm command
|
|
CALL SF_byte_write
|
|
CALL wait_SF_ready ;wait for erase to complete
|
|
RETURN
|
|
;
|
|
;
|
|
;**************************************************************************************
|
|
; Write a single byte to StrataFlash Memory
|
|
;**************************************************************************************
|
|
;
|
|
; To write a single byte to StrataFLASH memory the address must be set and the
|
|
; single-word/byte program command (40 hex) sent to the memory. Then the data byte can
|
|
; be written to the memory using the same address.
|
|
;
|
|
; The 24-bit address should be supplied in register set [s9,s8,s7].
|
|
; Register s0 should contain the byte data to be written to the memory.
|
|
;
|
|
; The act of writing the memory array may take up to 175us to complete. This routine
|
|
; waits for the memory to be ready before restoring the normal read array mode and
|
|
; returning.
|
|
;
|
|
; Registers used s0,s1,s7,s8,s9 (s7,s8,s9 not changed)
|
|
;
|
|
; Registers used s0,s1,s7,s8,s9
|
|
;
|
|
SF_single_byte_write: LOAD s1, 40 ;command for single byte program
|
|
CALL SF_byte_write
|
|
LOAD s1, s0 ;write data to be programmed
|
|
CALL SF_byte_write
|
|
CALL wait_SF_ready ;wait for program to complete
|
|
RETURN
|
|
;
|
|
;
|
|
;
|
|
;**************************************************************************************
|
|
; Read the unique 64-bit serial number of the StrataFLASH FLASH memory
|
|
;**************************************************************************************
|
|
;
|
|
; To read the device information the Read device information command (90)
|
|
; must be written to the memory. The information is read back from address 000102
|
|
; to 000109 (note these are byte access addresses).
|
|
;
|
|
; The serial number is copied to 8 ascending scratch pad memory locations called
|
|
; 'serial_number0' through to 'serial_number7' for future use.
|
|
;
|
|
; After reading the device information the read array command is written to the
|
|
; device to put it back to normal read mode.
|
|
;
|
|
; Registers used s0,s1,s2,s7,s8,s9
|
|
;
|
|
read_SF_serial_number: LOAD s9, 00 ;StrataFLASH address to read serial number = 000102
|
|
LOAD s8, 01
|
|
LOAD s7, 02
|
|
LOAD s2, serial_number0 ;pointer to scratch pad memory
|
|
LOAD s1, 90 ;command to read device information
|
|
CALL SF_byte_write
|
|
read_SN_loop: CALL SF_byte_read ;read serial number value
|
|
STORE s0, (s2)
|
|
COMPARE s2, serial_number7 ;check for 8 bytes copied
|
|
JUMP Z, end_read_SN
|
|
ADD s7, 01 ;increment StrataFLASH address
|
|
ADD s2, 01 ;increment memory pointer
|
|
JUMP read_SN_loop
|
|
;
|
|
end_read_SN: CALL set_SF_read_array_mode ;restore normal read array mode
|
|
RETURN
|
|
;
|
|
;
|
|
;
|
|
;**************************************************************************************
|
|
; Read a byte from StrataFlash Memory
|
|
;**************************************************************************************
|
|
;
|
|
; The 24-bit address should be supplied in register set [s9,s8,s7].
|
|
; Register s0 will return the byte data retrieved from the memory.
|
|
;
|
|
; To read a byte, the address needs to be set up on the address lines
|
|
; and the controls set as follows
|
|
; SF_read = 1 - disable Spartan data outputs and enable StrataFlash outputs (OE=0)
|
|
; SF_ce = 0 - enable StrataFLASH memory
|
|
; SF_we = 1 - Write enable off
|
|
;
|
|
; The access time of the memory is 75ns. This is equivalent to 3.75 clock cycles at
|
|
; 50MHz. Since each KCPSM3 instruction takes 2 clock cycles to execute, two instructions
|
|
; provides adequate delay for the memory to be accessed.
|
|
;
|
|
; Registers used s0,s1,s7,s8,s9
|
|
;
|
|
SF_byte_read: OUTPUT s9, SF_addr_hi_port ;set 24-bit address
|
|
OUTPUT s8, SF_addr_mi_port
|
|
OUTPUT s7, SF_addr_lo_port
|
|
LOAD s1, 05 ;set controls
|
|
OUTPUT s1, SF_control_port
|
|
LOAD s1, 06 ;>75ns delay
|
|
LOAD s1, 06 ;but do something useful!
|
|
INPUT s0, SF_data_in_port ;read data byte
|
|
OUTPUT s1, SF_control_port ;clear controls
|
|
RETURN
|
|
;
|
|
;
|
|
;**************************************************************************************
|
|
; Write data or command byte to StrataFlash Memory
|
|
;**************************************************************************************
|
|
;
|
|
; The 24-bit address should be supplied in register set [s9,s8,s7].
|
|
; Register s1 should contain the byte to be written to the memory.
|
|
;
|
|
; To write a byte, the address needs to be set up on the address lines
|
|
; and the controls set as follows
|
|
; SF_read = 0 - enable Spartan data outputs and disable StrataFlash outputs (OE=1)
|
|
; SF_ce = 0 - enable StrataFLASH memory
|
|
; SF_we = 0 - Write enable on
|
|
;
|
|
; The setup time of the memory is 60ns. This is equivalent to 3 clock cycles at
|
|
; 50MHz. Since each KCPSM3 instruction takes 2 clock cycles to execute, two instructions
|
|
; provides adequate delay for the memory.
|
|
;
|
|
; Registers used s1,s7,s8,s9
|
|
;
|
|
SF_byte_write: OUTPUT s9, SF_addr_hi_port ;set 24-bit address
|
|
OUTPUT s8, SF_addr_mi_port
|
|
OUTPUT s7, SF_addr_lo_port
|
|
OUTPUT s1, SF_data_out_port ;set data byte to be written
|
|
LOAD s1, 00 ;set controls
|
|
OUTPUT s1, SF_control_port
|
|
LOAD s1, 06 ;>60ns delay
|
|
LOAD s1, 06 ;but do something useful!
|
|
OUTPUT s1, SF_control_port ;clear controls
|
|
RETURN
|
|
;
|
|
;
|
|
;**************************************************************************************
|
|
; Set 'Read Array' mode on StrataFLASH
|
|
;**************************************************************************************
|
|
;
|
|
; The read array mode is the default mode of the memory and allows the contents
|
|
; of the memory to be read based on the supplied address.
|
|
;
|
|
; Read array is the default mode of the device, but it must also be placed back
|
|
; into this mode after programming, erasing or reading the status register.
|
|
;
|
|
; The read array command (FF hex) is written to the Strata flash memory.
|
|
;
|
|
; Registers used s1,s7,s8,s9
|
|
;
|
|
set_SF_read_array_mode: LOAD s1, FF ;command to read array
|
|
CALL SF_byte_write
|
|
RETURN
|
|
;
|
|
;
|
|
;**************************************************************************************
|
|
; Wait for StrataFLASH to be ready
|
|
;**************************************************************************************
|
|
;
|
|
; This routine will typically be used after instigating a program or erase
|
|
; command. It continuously reads the StrataFLASH status register and tests the
|
|
; information provided by bit7 which indicates if the memory is busy(0) or ready(1).
|
|
; The routine waits for the ready condition before sending a read array command
|
|
; which puts the memory back to normal read mode.
|
|
;
|
|
;
|
|
; Registers used s0,s1,s7,s8,s9 (s7,s8,s9 not changed)
|
|
;
|
|
;
|
|
wait_SF_ready: CALL SF_byte_read ;read status register into s0
|
|
TEST s0, 80 ;test ready/busy flag
|
|
JUMP Z, wait_SF_ready
|
|
CALL set_SF_read_array_mode ;restore normal read array mode
|
|
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 UART_data.
|
|
;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 UART_data, 61 ;eliminate character codes below 'a' (61 hex)
|
|
RETURN C
|
|
COMPARE UART_data, 7B ;eliminate character codes above 'z' (7A hex)
|
|
RETURN NC
|
|
AND UART_data, 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
|
|
;
|
|
;
|
|
;Send the six character HEX value of the register contents [s9,s8,s7] to the UART
|
|
;
|
|
;Registers used s0, s1, s2
|
|
;
|
|
send_hex_3bytes: LOAD s0, s9
|
|
CALL send_hex_byte
|
|
LOAD s0, s8
|
|
CALL send_hex_byte
|
|
LOAD s0, s7
|
|
CALL send_hex_byte
|
|
RETURN
|
|
;
|
|
;
|
|
;Display the two character HEX value of the register contents 's0' on the LCD display
|
|
;
|
|
;Registers used s0,s1,s2,s3,s4,s5
|
|
;
|
|
disp_hex_byte: CALL hex_byte_to_ASCII
|
|
LOAD s3, s1 ;remember least significant digit
|
|
LOAD s5, s2
|
|
CALL LCD_write_data ;display most significant digit
|
|
LOAD s5, s3
|
|
CALL LCD_write_data ;display least significant digit
|
|
RETURN
|
|
;
|
|
;
|
|
;
|
|
;**************************************************************************************
|
|
; UART 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 an equals sign to the UART with a space each side
|
|
;
|
|
send_equals: CALL send_space
|
|
LOAD UART_data, character_equals
|
|
CALL send_to_UART
|
|
CALL send_space
|
|
RETURN
|
|
;
|
|
;
|
|
;
|
|
;Send an minus sign (dash) to the UART with a space each side
|
|
;
|
|
send_dash: CALL send_space
|
|
LOAD UART_data, character_minus
|
|
CALL send_to_UART
|
|
CALL send_space
|
|
RETURN
|
|
;
|
|
;
|
|
;Send 'PicoBlaze Low Cost Design Security 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
|
|
LOAD UART_data, character_c
|
|
CALL send_to_UART
|
|
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
|
|
LOAD UART_data, character_a
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_z
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_e
|
|
CALL send_to_UART
|
|
CALL send_space
|
|
LOAD UART_data, character_L
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_o
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_w
|
|
CALL send_to_UART
|
|
CALL send_space
|
|
LOAD UART_data, character_C
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_o
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_s
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_t
|
|
CALL send_to_UART
|
|
CALL send_space
|
|
LOAD UART_data, character_D
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_e
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_s
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_i
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_g
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_n
|
|
CALL send_to_UART
|
|
CALL send_space
|
|
LOAD UART_data, character_S
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_e
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_c
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_u
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_r
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_i
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_t
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_y
|
|
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 'Copyright Ken Chapman 2006' string to the UART
|
|
;
|
|
;This message is significant because it demonstrates that the design
|
|
;now has a 'watermark'. The ASCII codes for this string will be
|
|
;stored in the design configuration bit stream somewhere as well as
|
|
;being played out by the UART. If someone tries to change or delete
|
|
;this message the contents of the BRAM will change and the hardware
|
|
;check of the BRAM contents will fail to match the expected value and
|
|
;the design will again be disabled.
|
|
;
|
|
send_Copyright: LOAD UART_data, character_C
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_o
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_p
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_y
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_r
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_i
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_g
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_h
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_t
|
|
CALL send_to_UART
|
|
CALL send_space
|
|
LOAD UART_data, character_K
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_e
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_n
|
|
CALL send_to_UART
|
|
CALL send_space
|
|
LOAD UART_data, character_C
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_h
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_a
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_p
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_m
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_a
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_n
|
|
CALL send_to_UART
|
|
CALL send_space
|
|
LOAD UART_data, character_2
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_0
|
|
CALL send_to_UART
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_6
|
|
CALL send_to_UART
|
|
CALL send_CR
|
|
CALL send_CR
|
|
RETURN
|
|
;
|
|
;
|
|
;
|
|
;Send 'FLASH ' string to the UART
|
|
;
|
|
send_FLASH: LOAD UART_data, character_F
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_L
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_A
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_S
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_H
|
|
CALL send_to_UART
|
|
RETURN
|
|
;
|
|
;
|
|
;
|
|
;Send 'FLASH Serial Number = ' string to the UART
|
|
;
|
|
send_FLASH_Serial_Number: CALL send_FLASH
|
|
CALL send_space
|
|
LOAD UART_data, character_S
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_e
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_r
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_i
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_a
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_l
|
|
CALL send_to_UART
|
|
CALL send_space
|
|
LOAD UART_data, character_N
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_u
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_m
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_b
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_e
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_r
|
|
CALL send_to_UART
|
|
CALL send_equals
|
|
RETURN
|
|
;
|
|
;
|
|
;Send 'Auth' string to the UART
|
|
;
|
|
send_Auth: LOAD UART_data, character_A
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_u
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_t
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_h
|
|
CALL send_to_UART
|
|
RETURN
|
|
;
|
|
;Send 'Authoris' to the UART
|
|
;
|
|
send_Authoris: CALL send_Auth
|
|
LOAD UART_data, character_o
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_r
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_i
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_s
|
|
CALL send_to_UART
|
|
RETURN
|
|
;
|
|
;Send 'Authorisation' to the UART
|
|
;
|
|
send_Authorisation: CALL send_Authoris
|
|
LOAD UART_data, character_a
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_t
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_i
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_o
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_n
|
|
CALL send_to_UART
|
|
RETURN
|
|
;
|
|
;Send 'Authorise' to the UART
|
|
;
|
|
send_Authorise: CALL send_Authoris
|
|
LOAD UART_data, character_e
|
|
CALL send_to_UART
|
|
RETURN
|
|
;
|
|
;Send 'Authentication' string to the UART
|
|
;
|
|
send_Authentication: CALL send_Auth
|
|
LOAD UART_data, character_e
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_n
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_t
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_i
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_c
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_a
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_t
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_i
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_o
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_n
|
|
CALL send_to_UART
|
|
RETURN
|
|
;
|
|
;
|
|
;Send 'FLASH CRC = ' string to the UART
|
|
;
|
|
send_FLASH_CRC: CALL send_FLASH
|
|
;
|
|
;
|
|
;Send ' CRC = ' string to the UART
|
|
;
|
|
send_CRC: CALL send_space
|
|
LOAD UART_data, character_C
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_R
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_C
|
|
CALL send_to_UART
|
|
CALL send_equals
|
|
RETURN
|
|
;
|
|
;
|
|
;
|
|
;Send 'Computed CRC = ' string to the UART
|
|
;
|
|
send_Computed_CRC: LOAD UART_data, character_C
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_o
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_m
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_p
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_u
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_t
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_e
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_d
|
|
CALL send_to_UART
|
|
JUMP send_CRC
|
|
;
|
|
;
|
|
;Send 'Erase ' string to the UART
|
|
;
|
|
send_Erase: LOAD UART_data, character_E
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_r
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_a
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_s
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_e
|
|
CALL send_to_UART
|
|
CALL send_space
|
|
RETURN
|
|
;
|
|
;
|
|
;Send 'Erase Authorisation in progress' string to the UART
|
|
;
|
|
send_Erase_in_progress: CALL send_CR
|
|
CALL send_Erase
|
|
CALL send_Authorisation
|
|
CALL send_space
|
|
LOAD UART_data, character_i
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_n
|
|
CALL send_to_UART
|
|
CALL send_space
|
|
LOAD UART_data, character_P
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_r
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_o
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_g
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_r
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_e
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_s
|
|
CALL send_to_UART
|
|
CALL send_to_UART
|
|
CALL send_CR
|
|
RETURN
|
|
;
|
|
;
|
|
;Send 'OK' to the UART
|
|
;
|
|
send_OK: LOAD UART_data, character_O
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_K
|
|
CALL send_to_UART
|
|
CALL send_CR
|
|
RETURN
|
|
;
|
|
;
|
|
;Send ' FAILED' to the UART
|
|
;
|
|
send_FAILED: CALL send_space
|
|
LOAD UART_data, character_F
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_A
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_I
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_L
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_E
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_D
|
|
CALL send_to_UART
|
|
RETURN
|
|
;
|
|
;
|
|
;Send ' PASSED' to the UART
|
|
;
|
|
send_PASSED: CALL send_space
|
|
LOAD UART_data, character_P
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_A
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_S
|
|
CALL send_to_UART
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_E
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_D
|
|
CALL send_to_UART
|
|
RETURN
|
|
;
|
|
;
|
|
;
|
|
;Send 'Writing Authorisation' to the UART
|
|
;
|
|
send_Writing: CALL send_CR
|
|
LOAD UART_data, character_W
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_r
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_i
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_t
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_i
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_n
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_g
|
|
CALL send_to_UART
|
|
CALL send_space
|
|
CALL send_Authorisation
|
|
RETURN
|
|
;
|
|
;Send simple menu of options to the UART
|
|
;
|
|
;
|
|
send_Menu: CALL send_CR
|
|
CALL send_CR
|
|
LOAD UART_data, character_M
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_e
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_n
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_u
|
|
CALL send_to_UART
|
|
CALL send_CR
|
|
CALL send_CR
|
|
LOAD UART_data, character_R
|
|
CALL send_to_UART
|
|
CALL send_dash
|
|
LOAD UART_data, character_R
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_e
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_a
|
|
CALL send_to_UART
|
|
LOAD UART_data, character_d
|
|
CALL send_to_UART
|
|
CALL send_space
|
|
CALL send_Authorisation
|
|
CALL send_CR
|
|
LOAD UART_data, character_E
|
|
CALL send_to_UART
|
|
CALL send_dash
|
|
CALL send_Erase
|
|
CALL send_Authorisation
|
|
CALL send_CR
|
|
LOAD UART_data, character_A
|
|
CALL send_to_UART
|
|
CALL send_dash
|
|
CALL send_Authorise
|
|
CALL send_CR
|
|
CALL send_CR
|
|
LOAD UART_data, character_greater_than ;prompt for input
|
|
CALL send_to_UART
|
|
RETURN
|
|
;
|
|
;**************************************************************************************
|
|
;LCD Character Module Routines
|
|
;**************************************************************************************
|
|
;
|
|
;LCD module is a 16 character by 2 line display but all displays are very similar
|
|
;The 4-wire data interface will be used (DB4 to DB7).
|
|
;
|
|
;The LCD modules are relatively slow and software delay loops are used to slow down
|
|
;KCPSM3 adequately for the LCD to communicate. The delay routines are provided in
|
|
;a different section (see above in this case).
|
|
;
|
|
;
|
|
;Pulse LCD enable signal 'E' high for greater than 230ns (1us is used).
|
|
;
|
|
;Register s4 should define the current state of the LCD output port.
|
|
;
|
|
;Registers used s0, s4
|
|
;
|
|
LCD_pulse_E: XOR s4, LCD_E ;E=1
|
|
OUTPUT s4, LCD_output_port
|
|
CALL delay_1us
|
|
XOR s4, LCD_E ;E=0
|
|
OUTPUT s4, LCD_output_port
|
|
RETURN
|
|
;
|
|
;Write 4-bit instruction to LCD display.
|
|
;
|
|
;The 4-bit instruction should be provided in the upper 4-bits of register s4.
|
|
;Note that this routine does not release the master enable but as it is only
|
|
;used during initialisation and as part of the 8-bit instruction write it
|
|
;should be acceptable.
|
|
;
|
|
;Registers used s4
|
|
;
|
|
LCD_write_inst4: AND s4, F8 ;Enable=1 RS=0 Instruction, RW=0 Write, E=0
|
|
OUTPUT s4, LCD_output_port ;set up RS and RW >40ns before enable pulse
|
|
CALL LCD_pulse_E
|
|
RETURN
|
|
;
|
|
;
|
|
;Write 8-bit instruction to LCD display.
|
|
;
|
|
;The 8-bit instruction should be provided in register s5.
|
|
;Instructions are written using the following sequence
|
|
; Upper nibble
|
|
; wait >1us
|
|
; Lower nibble
|
|
; wait >40us
|
|
;
|
|
;Registers used s0, s1, s4, s5
|
|
;
|
|
LCD_write_inst8: LOAD s4, s5
|
|
AND s4, F0 ;Enable=0 RS=0 Instruction, RW=0 Write, E=0
|
|
OR s4, LCD_drive ;Enable=1
|
|
CALL LCD_write_inst4 ;write upper nibble
|
|
CALL delay_1us ;wait >1us
|
|
LOAD s4, s5 ;select lower nibble with
|
|
SL1 s4 ;Enable=1
|
|
SL0 s4 ;RS=0 Instruction
|
|
SL0 s4 ;RW=0 Write
|
|
SL0 s4 ;E=0
|
|
CALL LCD_write_inst4 ;write lower nibble
|
|
CALL delay_40us ;wait >40us
|
|
LOAD s4, F0 ;Enable=0 RS=0 Instruction, RW=0 Write, E=0
|
|
OUTPUT s4, LCD_output_port ;Release master enable
|
|
RETURN
|
|
;
|
|
;
|
|
;
|
|
;Write 8-bit data to LCD display.
|
|
;
|
|
;The 8-bit data should be provided in register s5.
|
|
;Data bytes are written using the following sequence
|
|
; Upper nibble
|
|
; wait >1us
|
|
; Lower nibble
|
|
; wait >40us
|
|
;
|
|
;Registers used s0, s1, s4, s5
|
|
;
|
|
LCD_write_data: LOAD s4, s5
|
|
AND s4, F0 ;Enable=0 RS=0 Instruction, RW=0 Write, E=0
|
|
OR s4, 0C ;Enable=1 RS=1 Data, RW=0 Write, E=0
|
|
OUTPUT s4, LCD_output_port ;set up RS and RW >40ns before enable pulse
|
|
CALL LCD_pulse_E ;write upper nibble
|
|
CALL delay_1us ;wait >1us
|
|
LOAD s4, s5 ;select lower nibble with
|
|
SL1 s4 ;Enable=1
|
|
SL1 s4 ;RS=1 Data
|
|
SL0 s4 ;RW=0 Write
|
|
SL0 s4 ;E=0
|
|
OUTPUT s4, LCD_output_port ;set up RS and RW >40ns before enable pulse
|
|
CALL LCD_pulse_E ;write lower nibble
|
|
CALL delay_40us ;wait >40us
|
|
LOAD s4, F0 ;Enable=0 RS=0 Instruction, RW=0 Write, E=0
|
|
OUTPUT s4, LCD_output_port ;Release master enable
|
|
RETURN
|
|
;
|
|
;
|
|
;
|
|
;
|
|
;Read 8-bit data from LCD display.
|
|
;
|
|
;The 8-bit data will be read from the current LCD memory address
|
|
;and will be returned in register s5.
|
|
;It is advisable to set the LCD address (cursor position) before
|
|
;using the data read for the first time otherwise the display may
|
|
;generate invalid data on the first read.
|
|
;
|
|
;Data bytes are read using the following sequence
|
|
; Upper nibble
|
|
; wait >1us
|
|
; Lower nibble
|
|
; wait >40us
|
|
;
|
|
;Registers used s0, s1, s4, s5
|
|
;
|
|
LCD_read_data8: LOAD s4, 0E ;Enable=1 RS=1 Data, RW=1 Read, E=0
|
|
OUTPUT s4, LCD_output_port ;set up RS and RW >40ns before enable pulse
|
|
XOR s4, LCD_E ;E=1
|
|
OUTPUT s4, LCD_output_port
|
|
CALL delay_1us ;wait >260ns to access data
|
|
INPUT s5, LCD_input_port ;read upper nibble
|
|
XOR s4, LCD_E ;E=0
|
|
OUTPUT s4, LCD_output_port
|
|
CALL delay_1us ;wait >1us
|
|
XOR s4, LCD_E ;E=1
|
|
OUTPUT s4, LCD_output_port
|
|
CALL delay_1us ;wait >260ns to access data
|
|
INPUT s0, LCD_input_port ;read lower nibble
|
|
XOR s4, LCD_E ;E=0
|
|
OUTPUT s4, LCD_output_port
|
|
AND s5, F0 ;merge upper and lower nibbles
|
|
SR0 s0
|
|
SR0 s0
|
|
SR0 s0
|
|
SR0 s0
|
|
OR s5, s0
|
|
LOAD s4, 04 ;Enable=0 RS=1 Data, RW=0 Write, E=0
|
|
OUTPUT s4, LCD_output_port ;Stop reading 5V device and release master enable
|
|
CALL delay_40us ;wait >40us
|
|
RETURN
|
|
;
|
|
;
|
|
;Reset and initialise display to communicate using 4-bit data mode
|
|
;Includes routine to clear the display.
|
|
;
|
|
;Requires the 4-bit instructions 3,3,3,2 to be sent with suitable delays
|
|
;following by the 8-bit instructions to set up the display.
|
|
;
|
|
; 28 = '001' Function set, '0' 4-bit mode, '1' 2-line, '0' 5x7 dot matrix, 'xx'
|
|
; 06 = '000001' Entry mode, '1' increment, '0' no display shift
|
|
; 0C = '00001' Display control, '1' display on, '0' cursor off, '0' cursor blink off
|
|
; 01 = '00000001' Display clear
|
|
;
|
|
;Registers used s0, s1, s2, s3, s4
|
|
;
|
|
LCD_reset: CALL delay_20ms ;wait more that 15ms for display to be ready
|
|
LOAD s4, 30
|
|
CALL LCD_write_inst4 ;send '3'
|
|
CALL delay_20ms ;wait >4.1ms
|
|
CALL LCD_write_inst4 ;send '3'
|
|
CALL delay_1ms ;wait >100us
|
|
CALL LCD_write_inst4 ;send '3'
|
|
CALL delay_40us ;wait >40us
|
|
LOAD s4, 20
|
|
CALL LCD_write_inst4 ;send '2'
|
|
CALL delay_40us ;wait >40us
|
|
LOAD s5, 28 ;Function set
|
|
CALL LCD_write_inst8
|
|
LOAD s5, 06 ;Entry mode
|
|
CALL LCD_write_inst8
|
|
LOAD s5, 0C ;Display control
|
|
CALL LCD_write_inst8
|
|
LCD_clear: LOAD s5, 01 ;Display clear
|
|
CALL LCD_write_inst8
|
|
CALL delay_1ms ;wait >1.64ms for display to clear
|
|
CALL delay_1ms
|
|
RETURN
|
|
;
|
|
;Position the cursor ready for characters to be written.
|
|
;The display is formed of 2 lines of 16 characters and each
|
|
;position has a corresponding address as indicated below.
|
|
;
|
|
; Character position
|
|
; 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
|
;
|
|
; Line 1 - 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
|
|
; Line 2 - C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
|
|
;
|
|
;This routine will set the cursor position using the value provided
|
|
;in register s5. The upper nibble will define the line and the lower
|
|
;nibble the character position on the line.
|
|
; Example s5 = 2B will position the cursor on line 2 position 11
|
|
;
|
|
;Registers used s0, s1, s2, s3, s4
|
|
;
|
|
LCD_cursor: TEST s5, 10 ;test for line 1
|
|
JUMP Z, set_line2
|
|
AND s5, 0F ;make address in range 80 to 8F for line 1
|
|
OR s5, 80
|
|
CALL LCD_write_inst8 ;instruction write to set cursor
|
|
RETURN
|
|
set_line2: AND s5, 0F ;make address in range C0 to CF for line 2
|
|
OR s5, C0
|
|
CALL LCD_write_inst8 ;instruction write to set cursor
|
|
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
|
|
;
|
|
;Registers 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.
|
|
;
|
|
;Delay of 20ms used during initialisation.
|
|
;
|
|
;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, 32 ;50 x 20ms = 1000ms
|
|
wait_1s: CALL delay_20ms
|
|
SUB s4, 01
|
|
JUMP NZ, wait_1s
|
|
RETURN
|
|
;
|
|
;
|
|
;Delay of approximately N seconds where 'N' is provided in register s5.
|
|
;
|
|
;Registers used s0, s1, s2, s3, s4, s5
|
|
;
|
|
delay_Ns: CALL delay_1s
|
|
SUB s5, 01
|
|
JUMP NZ, delay_Ns
|
|
RETURN
|
|
;
|
|
;
|
|
;
|
|
;**************************************************************************************
|
|
;LCD text messages
|
|
;**************************************************************************************
|
|
;
|
|
;
|
|
;
|
|
;Display 'PicoBlaze' on LCD at current cursor position
|
|
;
|
|
;
|
|
disp_PicoBlaze: LOAD s5, character_P
|
|
CALL LCD_write_data
|
|
LOAD s5, character_i
|
|
CALL LCD_write_data
|
|
LOAD s5, character_c
|
|
CALL LCD_write_data
|
|
LOAD s5, character_o
|
|
CALL LCD_write_data
|
|
LOAD s5, character_B
|
|
CALL LCD_write_data
|
|
LOAD s5, character_l
|
|
CALL LCD_write_data
|
|
LOAD s5, character_a
|
|
CALL LCD_write_data
|
|
LOAD s5, character_z
|
|
CALL LCD_write_data
|
|
LOAD s5, character_e
|
|
CALL LCD_write_data
|
|
RETURN
|
|
;
|
|
;
|
|
;Display 'Security' on LCD at current cursor position
|
|
;
|
|
;
|
|
disp_Security: LOAD s5, character_S
|
|
CALL LCD_write_data
|
|
LOAD s5, character_e
|
|
CALL LCD_write_data
|
|
LOAD s5, character_c
|
|
CALL LCD_write_data
|
|
LOAD s5, character_u
|
|
CALL LCD_write_data
|
|
LOAD s5, character_r
|
|
CALL LCD_write_data
|
|
LOAD s5, character_i
|
|
CALL LCD_write_data
|
|
LOAD s5, character_t
|
|
CALL LCD_write_data
|
|
LOAD s5, character_y
|
|
CALL LCD_write_data
|
|
RETURN
|
|
;
|
|
;
|
|
;Display 'FLASH Serial No.' on LCD at current cursor position
|
|
;
|
|
;
|
|
disp_FLASH_Serial_No: LOAD s5, character_F
|
|
CALL LCD_write_data
|
|
LOAD s5, character_L
|
|
CALL LCD_write_data
|
|
LOAD s5, character_A
|
|
CALL LCD_write_data
|
|
LOAD s5, character_S
|
|
CALL LCD_write_data
|
|
LOAD s5, character_H
|
|
CALL LCD_write_data
|
|
LOAD s5, character_space
|
|
CALL LCD_write_data
|
|
LOAD s5, character_S
|
|
CALL LCD_write_data
|
|
LOAD s5, character_e
|
|
CALL LCD_write_data
|
|
LOAD s5, character_r
|
|
CALL LCD_write_data
|
|
LOAD s5, character_i
|
|
CALL LCD_write_data
|
|
LOAD s5, character_a
|
|
CALL LCD_write_data
|
|
LOAD s5, character_l
|
|
CALL LCD_write_data
|
|
LOAD s5, character_space
|
|
CALL LCD_write_data
|
|
LOAD s5, character_N
|
|
CALL LCD_write_data
|
|
LOAD s5, character_o
|
|
CALL LCD_write_data
|
|
LOAD s5, character_fullstop
|
|
CALL LCD_write_data
|
|
RETURN
|
|
;
|
|
;
|
|
;
|
|
;Display 'Authentication' on top line of the LCD
|
|
;
|
|
;
|
|
disp_Authentication: LOAD s5, 11 ;Line 1 position 1
|
|
CALL LCD_cursor
|
|
LOAD s5, character_A
|
|
CALL LCD_write_data
|
|
LOAD s5, character_u
|
|
CALL LCD_write_data
|
|
LOAD s5, character_t
|
|
CALL LCD_write_data
|
|
LOAD s5, character_h
|
|
CALL LCD_write_data
|
|
LOAD s5, character_e
|
|
CALL LCD_write_data
|
|
LOAD s5, character_n
|
|
CALL LCD_write_data
|
|
LOAD s5, character_t
|
|
CALL LCD_write_data
|
|
LOAD s5, character_i
|
|
CALL LCD_write_data
|
|
LOAD s5, character_c
|
|
CALL LCD_write_data
|
|
LOAD s5, character_a
|
|
CALL LCD_write_data
|
|
LOAD s5, character_t
|
|
CALL LCD_write_data
|
|
LOAD s5, character_i
|
|
CALL LCD_write_data
|
|
LOAD s5, character_o
|
|
CALL LCD_write_data
|
|
LOAD s5, character_n
|
|
CALL LCD_write_data
|
|
RETURN
|
|
;
|
|
;
|
|
;
|
|
;
|
|
;Display 'Passed' on lower line of the LCD
|
|
;
|
|
;
|
|
disp_Passed: LOAD s5, 25 ;Line 2 position 5
|
|
CALL LCD_cursor
|
|
LOAD s5, character_P
|
|
CALL LCD_write_data
|
|
LOAD s5, character_a
|
|
CALL LCD_write_data
|
|
LOAD s5, character_s
|
|
CALL LCD_write_data
|
|
CALL LCD_write_data
|
|
LOAD s5, character_e
|
|
CALL LCD_write_data
|
|
LOAD s5, character_d
|
|
CALL LCD_write_data
|
|
RETURN
|
|
;
|
|
;
|
|
;
|
|
;
|
|
;
|
|
;Display 'Failed' on lower line of the LCD
|
|
;
|
|
;
|
|
disp_Failed: LOAD s5, 25 ;Line 2 position 5
|
|
CALL LCD_cursor
|
|
LOAD s5, character_F
|
|
CALL LCD_write_data
|
|
LOAD s5, character_a
|
|
CALL LCD_write_data
|
|
LOAD s5, character_i
|
|
CALL LCD_write_data
|
|
LOAD s5, character_l
|
|
CALL LCD_write_data
|
|
LOAD s5, character_e
|
|
CALL LCD_write_data
|
|
LOAD s5, character_d
|
|
CALL LCD_write_data
|
|
RETURN
|
|
;
|
|
;
|
|
;**************************************************************************************
|
|
; Interrupt Service Routine (ISR)
|
|
;**************************************************************************************
|
|
;
|
|
; Interrupts occur when the application processor is requesting a design authorisation
|
|
; message. Therefore an interrupt results in a message being sent to the Link FIFO
|
|
; depending on the authentication status.
|
|
;
|
|
ISR: STORE s0, ISR_preserve_s0 ;save register contents
|
|
;
|
|
FETCH s0, authentication_status ;read authentication status
|
|
COMPARE s0, character_P ;test for pass 'P' or fail 'F'
|
|
JUMP Z, pass_token
|
|
;
|
|
LOAD s0, character_F ;send FAIL to link FIFO
|
|
OUTPUT s0, link_FIFO_write_port
|
|
LOAD s0, character_A
|
|
OUTPUT s0, link_FIFO_write_port
|
|
LOAD s0, character_I
|
|
OUTPUT s0, link_FIFO_write_port
|
|
LOAD s0, character_L
|
|
OUTPUT s0, link_FIFO_write_port
|
|
JUMP end_ISR
|
|
;
|
|
pass_token: OUTPUT s0, link_FIFO_write_port ;send PASS to link FIFO
|
|
LOAD s0, character_A
|
|
OUTPUT s0, link_FIFO_write_port
|
|
LOAD s0, character_S
|
|
OUTPUT s0, link_FIFO_write_port
|
|
OUTPUT s0, link_FIFO_write_port
|
|
;
|
|
end_ISR: FETCH s0, ISR_preserve_s0 ;restore register contents
|
|
RETURNI ENABLE
|
|
;
|
|
;
|
|
;**************************************************************************************
|
|
; Interrupt Vector
|
|
;**************************************************************************************
|
|
;
|
|
ADDRESS 3FF
|
|
JUMP ISR
|
|
;
|
|
;
|
|
;**************************************************************************************
|
|
; End of Program
|
|
;**************************************************************************************
|