1
0
mirror of https://github.com/pConst/basic_verilog.git synced 2025-01-28 07:02:55 +08:00

1678 lines
93 KiB
Plaintext

;KCPSM3 Program - UART programming of SPI Flash memory on Spartan-3E Starter Kit.
;
;
;Ken Chapman - Xilinx Ltd
;
;Version v1.00 - 11th November 2005
;
;This program uses a 115200 baud UART connection with XON/XOFF flow control
;to allow a standard MCS file for the configuration of a Spartan-3E device to
;be programmed into the ST Microelectronics M25P16 device on the board.
;
;
;
;As well as the port connections vital to communication with the UART and the SPI
;FLASH memory, there are additional port connections used to disable the other
;devices sharing the SPI bus on the Starter Kit board. Although these could have been
;controlled at the hardware level, they are included in this code to aid
;future investigations of communication with the other SPI devices using PicoBlaze.
;
;
;
;
;Port definitions
;
CONSTANT status_port, 00 ;UART and filter status input
CONSTANT tx_data_present, 01 ; Transmitter data present - bit0
CONSTANT tx_half_full, 02 ; FIFO half full - bit1
CONSTANT tx_full, 04 ; full - bit2
CONSTANT rx_data_present, 08 ; data present - bit3
CONSTANT rx_half_full, 10 ; Receiver half full - bit4
CONSTANT rx_full, 20 ; FIFO full - bit5
;
CONSTANT UART_read_port, 01 ;UART Rx data input
;
CONSTANT UART_write_port, 10 ;UART Tx data output
;
;
CONSTANT SPI_control_port, 08 ;SPI clock and chip selects
CONSTANT SPI_sck, 01 ; SCK - bit0
CONSTANT SPI_rom_cs, 02 ; serial rom select - bit1
CONSTANT SPI_spare_control, 04 ; spare - bit2
CONSTANT SPI_amp_cs, 08 ; amplifier select - bit3
CONSTANT SPI_adc_conv, 10 ; A/D convert - bit4
CONSTANT SPI_dac_cs, 20 ; D/A select - bit5
CONSTANT SPI_amp_shdn, 40 ; amplifier SHDN - bit6
CONSTANT SPI_dac_clr, 80 ; D/A clear - bit7
;
CONSTANT SPI_output_port, 04 ;SPI data output
CONSTANT SPI_sdo, 80 ; SDO - bit7
;
CONSTANT SPI_input_port, 02 ;SPI data input
CONSTANT SPI_sdi, 80 ; SDI - bit7
CONSTANT SPI_amp_sdi, 40 ; amplifier SDI - bit6
;
;
;
;
;Special Register usage
;
NAMEREG sF, UART_data ;used to pass data to and from the UART
;
;
;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
;
;
;Useful constants
;
;
;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
;
;
;Scratch Pad Memory Locations
;
;
CONSTANT ISR_preserve_s0, 00 ;preserve register during ISR
;
CONSTANT page_address_h, 01 ;Remember page address for SPI boundary checking.
CONSTANT page_address_m, 02 ;high, middle and low bytes
CONSTANT page_address_l, 03
;
CONSTANT SPI_control_status, 04 ;SPI status signals
;
;
;
;Store up to one line of an MCS file as bytes
;A typical data line consists of:-
;: Start character which is not stored
;10 Number of data bytes included (16 in this case)
;aaaa Lower 16-bits of the storage address
;00 Record type (data in this case)
;dddd... Data bytes (typically 16 which is the maximum)
;cc Checksum
;CR/LF Line will end in carriage return and/or line feed which is not stored.
;
;So a total of 21 could be stored before processing.
;
CONSTANT line_start, 2B ;21 bytes until end of memory
;
;
;Initialise the system and welcome message
;
;
cold_start: CALL SPI_init ;initialise SPI bus ports
CALL delay_1s ;delay because UART is fast and JTAG startup sequence can be slow
ENABLE INTERRUPT ;Interrupt is used for XON/XOFF flow control
welcome_start: CALL send_CR
CALL send_welcome ;start up message and version number
;
;Main menu and command selection
;
;
;
warm_start: CALL send_Menu ;Menu and command selection
prompt: CALL send_CR
CALL send_CR
LOAD UART_data, character_greater_than ;prompt for input
CALL send_to_UART
CALL read_upper_case
COMPARE s0, character_E ;command test
JUMP Z, erase_command
COMPARE s0, character_S ;command test
JUMP Z, sector_erase_command
COMPARE s0, character_P ;command test
JUMP Z, program_command
COMPARE s0, character_R ;command test
JUMP Z, read_command
COMPARE s0, character_I ;command test
JUMP Z, ID_command
COMPARE s0, character_H ;command test
JUMP Z, welcome_start
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 prompt ;Try again!
;
;
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
;
;**************************************************************************************
;ID Command - Read and display the ID for the SPI FLASH memory
;**************************************************************************************
;
;Normal response should be
; s9 = Manufacturer Identification = 20 hex
; s8 = Memory Type = 20 hex
; s7 = Memory Capacity = 15 hex
;
ID_command: CALL send_CR
CALL read_spi_flash_ID
CALL send_ID
LOAD UART_data, character_equals
CALL send_to_UART
CALL send_space
LOAD s0, s9
CALL send_hex_byte
CALL send_space
LOAD s0, s8
CALL send_hex_byte
CALL send_space
LOAD s0, s7
CALL send_hex_byte
CALL send_space
CALL send_CR
JUMP prompt
;
;**************************************************************************************
;Erase Command - Perform bulk erase of the SPI FLASH memory and display messages
;**************************************************************************************
;
erase_command: CALL send_CR
CALL send_Confirm ;confirm command with a 'Y' which must be upper case
CALL read_from_UART ;read command character from UART
CALL send_to_UART ;echo input
COMPARE UART_data, character_Y
JUMP NZ, abort_erase
CALL send_CR
CALL send_Erase_in_progress
CALL bulk_erase_spi
CALL send_OK
JUMP prompt
;
abort_erase: CALL send_Abort
JUMP prompt
;
;
;**************************************************************************************
;Sector Erase Command - Performs erase of lowest 5 sectors SPI FLASH memory which
;covers the address range 000000 to 04FFFF in which the configuration for an XC3S500E
;would be able to fit.
;**************************************************************************************
;
sector_erase_command: CALL send_CR
CALL send_Confirm ;confirm command with a 'Y' which must be upper case
CALL read_from_UART ;read command character from UART
CALL send_to_UART ;echo input
COMPARE UART_data, character_Y
JUMP NZ, abort_erase
CALL send_CR
CALL send_Erase_in_progress
LOAD s9, 00 ;any address inside sector 0
CALL erase_spi_sector
LOAD s9, 01 ;any address inside sector 1
CALL erase_spi_sector
LOAD s9, 02 ;any address inside sector 2
CALL erase_spi_sector
LOAD s9, 03 ;any address inside sector 3
CALL erase_spi_sector
LOAD s9, 04 ;any address inside sector 4
CALL erase_spi_sector
CALL send_OK
JUMP prompt
;
;
;**************************************************************************************
;Program Command - Program SPI FLASH memory with MCS file
;**************************************************************************************
;
program_command: CALL send_CR
CALL send_Waiting_MCS_file
CALL program_MCS
CALL send_OK
JUMP prompt
;
;
;**************************************************************************************
;Read Command - Read one page of memory at specified address
;**************************************************************************************
;
read_command: CALL send_page_address ;obtain 24-bit address
CALL obtain_8bits
JUMP C, read_command ;bad input address
COMPARE s0, 20 ;test for address greater than 1FFFFF
JUMP NC, read_command ;value too big
LOAD s9, s0
CALL obtain_8bits
JUMP C, read_command ;bad input address
LOAD s8, s0
CALL obtain_8bits
JUMP C, read_command ;bad input address
LOAD s7, s0
CALL send_CR
CALL send_spi_page
CALL send_OK
JUMP prompt
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
;
;
;
;**************************************************************************************
;Program SPI FLASH with MCS file
;**************************************************************************************
;
;Reads the MCS file from the UART and programs the SPI FLASH device at the locations.
;specified by the file contents.
;
;One important factor of programming the SPI FLASH for use as configuration
;memory is that the bits within each byte must be in reverse order. This
;is because an SPI device outputs data MSB first compared with a Xilinx
;serial PROM which outputs LSB first. Therefore this routine will swap
;the bits of each byte provided by the MCS file before programming.
;
;This routine will continue until an end of file record is detected.
;For each line of MCS received, the current address will be output so that
;progress can be monitored.
;
;Register sA is used to remember if a page is currently open (01) or closed (00)
;for writing on the SPI memory.
;
program_MCS: LOAD sA, 00 ;page is closed
next_prog_line: CALL read_MCS_line ;read line
CALL MCS_address ;find start address and record type
COMPARE sB, 01 ;test for end record
JUMP Z, end_program_MCS
CALL send_hex_3bytes ;send address for other lines
CALL send_CR
COMPARE sB, 04 ;test for extended address record
JUMP Z, MCS_address_boundary
;
;Assume data record type 00 now and program SPI page
;
SUB sE, 01 ;location of checksum just after last stored data byte
LOAD sD, line_start ;Point to first data byte
ADD sD, 04
COMPARE sA, 00 ;check if page is closed
JUMP Z, program_byte ;jump if page needs to be opened
FETCH s2, page_address_h ;check new address is sequential
COMPARE s2, s9
JUMP NZ, addr_out_of_sequence
FETCH s2, page_address_m ;check new address is sequential
COMPARE s2, s8
JUMP NZ, addr_out_of_sequence
FETCH s2, page_address_l ;check new address is sequential
COMPARE s2, s7
JUMP Z, program_byte ;continue with open page
addr_out_of_sequence: CALL close_prog_page_spi ;close page because address out of sequence
LOAD sA, 00 ;page is now closed
program_byte: COMPARE sA, 00 ;check if page is closed
JUMP NZ, page_is_open ;jump is page already open
CALL open_prog_page_spi ;open page with address [s9,s8,s7]
LOAD sA, 01 ;page is open
page_is_open: FETCH s1, (sD) ;fetch data byte
LOAD s0, 08 ;reverse order of bits
swap_bits: SR0 s1
SLA s2
SUB s0, 01
JUMP NZ, swap_bits ;swapped bits now in s2
CALL SPI_FLASH_tx_rx ;program byte into SPI memory
ADD s7, 01 ;increment address to keep track
ADDCY s8, 00
ADDCY s9, 00
COMPARE s7, 00 ;test if crossing page boundary FF to 00
JUMP NZ, byte_programmed
CALL close_prog_page_spi
LOAD sA, 00 ;page is now closed
byte_programmed: ADD sD, 01 ;move to next byte
COMPARE sD, sE ;check for last on line
JUMP NZ, program_byte ;fetch next byte to program
STORE s9, page_address_h ;remember next address in sequence
STORE s8, page_address_m
STORE s7, page_address_l
JUMP next_prog_line ;read next line for programming
MCS_address_boundary: COMPARE sA, 00 ;check if page needs to be closed
JUMP Z, next_prog_line
CALL close_prog_page_spi
JUMP program_MCS
end_program_MCS: COMPARE sA, 00 ;check if page needs to be closed
RETURN Z
CALL close_prog_page_spi
RETURN
;
;**************************************************************************************
;Read one line of an MCS file into scratch pad memory
;**************************************************************************************
;
;Reads one line of MCS file format into scratch pad memory starting at location 'line_start'.
;
;The routine detects the line start character ':' ignoring any preceding characters. This
;will remove any additional CR or LF characters.
;
;It then reads each subsequent pair of ASCII characters, converts them to true hex in the
;range 00 to FF and stores them in scratch pad memory.
;
;The end of the line is determined by either a CR or LF character.
;
;The value last returned in register 'sE' will be the pointer to the location in
;scratch pad memory following the last byte for the line read.
;
read_MCS_line: LOAD sE, line_start ;initialise SPM memory pointer
wait_MCS_line_Start: CALL read_from_UART ;read character
COMPARE UART_data, character_colon ;test for start character
JUMP NZ, wait_MCS_line_Start
read_MCS_byte: CALL read_from_UART ;read character
COMPARE UART_data, character_CR ;test for end of line
RETURN Z
COMPARE UART_data, character_LF ;test for end of line
RETURN Z
LOAD s3, UART_data ;upper nibble character
CALL read_from_UART ;read character
LOAD s2, UART_data ;lower nibble character
CALL ASCII_byte_to_hex ;convert to true hex value
STORE s0, (sE) ;write to SPM
ADD sE, 01 ;increment pointer
JUMP read_MCS_byte
;
;
;**************************************************************************************
;Determine the current address for the line of an MCS file in scratch pad memory
;**************************************************************************************
;
;Checks the existing line data stored in scratch pad memory starting at location
;'line_start' and determines the current address.
;
;The address is in the register set [s9,s8,s7] before and after this routine is
;executed because not all address bits are defined by a given line of MCS and
;the undefined bits remain constant.
;
;A record type of 04 will update [s9].
;A record type of 00 will update [s8,s7].
;
;On return, the register sB will contain the record type and
;register sC will indicate the number of data bytes stored.
;
MCS_address: LOAD sD, line_start ;initialise SPM memory pointer
FETCH sC, (sD) ;read number of bytes on line
ADD sD, 03 ;move to record type
FETCH sB, (sD) ;read record type
COMPARE sB, 00 ;test for data record
JUMP Z, new_low_address
COMPARE sB, 04 ;test for data record
RETURN NZ
ADD sD, 02 ;read upper 8-bits
FETCH s9, (sD)
RETURN
new_low_address: SUB sD, 01 ;read lower 8-bits
FETCH s7, (sD)
SUB sD, 01 ;read middle 8-bits
FETCH s8, (sD)
RETURN
;
;**************************************************************************************
;Read a page from SPI FLASH memory and display
;**************************************************************************************
;
;The start address should be provided in register set [s9,s8,s7].
;The display will be next 256 bytes displayed as 16 lines of 16 bytes
;with each line commencing with the address of the first byte.
;
;
send_spi_page: LOAD s6, 10 ;16 lines to display
send_spi_line: CALL send_CR
CALL send_hex_3bytes ;display address
CALL send_space
LOAD s5, 10 ;16 lines to display
send_spi_byte: CALL send_space
CALL read_spi_byte ;read byte into s2
ADD s7, 01 ;increment SPI FLASH address
ADDCY s8, 00
ADDCY s9, 00
LOAD s0, s2 ;display byte
CALL send_hex_byte
SUB s5, 01 ;count bytes per line
JUMP NZ, send_spi_byte
SUB s6, 01 ;count lines
JUMP NZ, send_spi_line
CALL send_CR
RETURN
;
;**************************************************************************************
;Test of SPI FLASH memory operations
;**************************************************************************************
;
;Sector 18 (120000 to 12FFFF) is used.
;A page (123400 to 1234FF) is programmed with a test pattern 00 to FF.
;The pattern is verified and then the sector erased and a blank check performed.
;
;Note that the page used is already blank (all locations contain FF hex)
;as with any device supplied (initial delivery state).
;
;Program page with test pattern
;
memory_test: LOAD s9, 12 ;select page address 123400
LOAD s8, 34
LOAD s7, 00
CALL open_prog_page_spi ; program test pattern 00 to FF
pattern_loop: LOAD s2, s7
CALL SPI_FLASH_tx_rx
ADD s7, 01
JUMP NC, pattern_loop
CALL close_prog_page_spi ; program test pattern 00 to FF
;
;Verify test pattern by reading back page
;
LOAD UART_data, character_p ;p for pass
LOAD s9, 12 ;select page address 123400
LOAD s8, 34
LOAD s7, 00
verify_test_page: CALL read_spi_byte ;read byte into s2
COMPARE s2, s7 ;check test pattern data value
JUMP NZ, memory_verify_fail
ADD s7, 01 ;next location
JUMP NZ, verify_test_page ;loop until roll over page
JUMP memory_verify_result
memory_verify_fail: LOAD UART_data, character_f ;f for fail
memory_verify_result: CALL send_to_UART
RETURN
;
;Erase sector with test pattern and verify blank
;
erase_test_sector: LOAD s9, 12 ;sector 18 start address 120000
LOAD s8, 00
LOAD s7, 00
CALL erase_spi_sector
LOAD UART_data, character_p ;p for pass
LOAD s9, 12 ;select page address 123400
LOAD s8, 34
LOAD s7, 00
verify_blank_page: CALL read_spi_byte ;read byte into s2
COMPARE s2, FF ;check blank 'FF'
JUMP NZ, memory_blank_fail
ADD s7, 01 ;next location
JUMP NZ, verify_blank_page ;loop until roll over page
JUMP memory_blank_result
memory_blank_fail: LOAD UART_data, character_f ;f for fail
memory_blank_result: CALL send_to_UART
RETURN
;
;
;
;**************************************************************************************
;Test of SPI FLASH memory communications
;**************************************************************************************
;Link must be installed in J11 to link ROM-CS to CSO_B
;
;Read the identification ID from SPI FLASH memory (ST type M25P16)
;and compare with expected response.
; s9 = Manufacturer Identification = 20 hex
; s8 = Memory Type = 20 hex
; s7 = Memory Capacity = 15 hex
;
memory_comms_test: CALL read_spi_flash_ID
LOAD UART_data, character_p ;p for pass
COMPARE s9, 20
JUMP NZ, SPI_FLASH_ID_fail
COMPARE s8, 20
JUMP NZ, SPI_FLASH_ID_fail
COMPARE s7, 15
JUMP NZ, SPI_FLASH_ID_fail
JUMP SPI_FLASH_ID_result
SPI_FLASH_ID_fail: LOAD UART_data, character_f ;f for fail
SPI_FLASH_ID_result: CALL send_to_UART
RETURN
;
;
;
;
;
;
;**************************************************************************************
;SPI FLASH memory routines
;**************************************************************************************
;
;These routines will work with two output ports and one input port which should be
;defined as follows using CONSTANT directives.
; (replace 'pp' with appropriate port address in each case)
;In the list of CONSTANT directives, only the ones marked with a * are really required
;in an SPI FLASH memory system. The other directives are to control (disable) or
;communicate with the other SPI components on the same SPI bus of the Spartan-3E Starter Kit.
;
;
;
;CONSTANT SPI_control_port, pp ;SPI clock and chip selects *
;CONSTANT SPI_sck, 01 ; SCK - bit0 *
;CONSTANT SPI_rom_cs, 02 ; serial rom select - bit1 *
;CONSTANT SPI_spare_control, 04 ; spare - bit2
;CONSTANT SPI_amp_cs, 08 ; amplifier select - bit3
;CONSTANT SPI_adc_conv, 10 ; A/D convert - bit4
;CONSTANT SPI_dac_cs, 20 ; D/A select - bit5
;CONSTANT SPI_amp_shdn, 40 ; amplifier SHDN - bit6
;CONSTANT SPI_dac_clr, 80 ; D/A clear - bit7
;
;CONSTANT SPI_output_port, pp ;SPI data output *
;CONSTANT SPI_sdo, 80 ; SDO - bit7 *
;
;CONSTANT SPI_input_port, pp ;SPI data input *
;CONSTANT SPI_sdi, 80 ; SDI - bit7 *
;CONSTANT SPI_amp_sdi, 40 ; amplifier SDI - bit6
;
;
;A single scratch pad memory location is also employed to remember the status of
;the SPI_control_port. This memory location must be defined as follows.
; (replace 'ss' with appropriate memory location)
;
;CONSTANT SPI_control_status, ss ;SPI status signals
;
;Not all the SPI routines will use this memory location because although they
;will change the bits on the control port, they will leave them in the same state
;as they were in when they started.
;
;
;
;
;Initialise SPI bus
;
;This routine should be used to initialise the SPI bus.
;The SCK clock is made low.
;Device selections are made inactive as follows
; SPI_sck = 0 Clock is Low (required)
; SPI_rom_cs = 1 Deselect ROM
; spare = 1 spare control bit
; SPI_amp_cs = 1 Deselect amplifier
; SPI_adc_conv = 0 A/D convert ready to apply positive pulse
; SPI_dac_cs = 1 Deselect D/A
; SPI_amp_shdn = 0 Amplifier active and available
; SPI_dac_clr = 1 D/A clear off
;
SPI_init: LOAD s0, AE ;normally AE
OUTPUT s0, SPI_control_port
STORE s0, SPI_control_status ;preserve status
RETURN
;
;
;Send and receive one byte to or from the SPI FLASH memory.
;
;The data supplied in register 's2' is transmitted to the SPI bus and
;at the same time any received byte is used to replace the value in 's2'.
;The SCK clock is generated by software and results in a communication rate of
;2.5Mbit/s with a 50MHz clock.
;
;Note that you must have previously selected the required device on the bus
;before attempting communication and you must subsequently deselect the device
;when appropriate.
;
;Entry to this routine assumes that SCK is already Low and the clock will be Low
;at the end of execution (provided in scratch pad memory location SPI_control_status).
;
;As a 'master' the signal sequence is as follows..
; Receive data bit from SDI line (Flash transmits on previous falling edge)
; Transmit data bit on SDO line
; Drive SCK transition from low to high
; Drive SCK transition from high to low.
;
SPI_FLASH_tx_rx: LOAD s1, 08 ;8-bits to transmit and receive
FETCH s0, SPI_control_status ;read control status bits
next_SPI_FLASH_bit: OUTPUT s2, SPI_output_port ;output data bit ready to be used on rising edge
INPUT s3, SPI_input_port ;read input bit
TEST s3, SPI_sdi ;detect state of received bit
SLA s2 ;shift new data into result and move to next transmit bit
XOR s0, SPI_sck ;clock High (bit0)
OUTPUT s0, SPI_control_port ;drive clock High
XOR s0, SPI_sck ;clock Low (bit0)
OUTPUT s0, SPI_control_port ;drive clock Low
SUB s1, 01 ;count bits
JUMP NZ, next_SPI_FLASH_bit ;repeat until finished
RETURN
;
;
;Read status register from SPI FLASH memory (ST type M25P16)
;
;Transmits instruction 05hex and then receives one byte in response
;which is returned in register s2.
;
; bit meaning
; 7 SRWD Status Register Write Protect
; 6 '0'
; 5 '0'
; 4 BP2 Block protect bit
; 3 BP1 Block protect bit
; 2 BP0 Block protect bit
; 1 WEL Write Enable Latch Bit
; 0 WIP Write In Progress
;
;
read_spi_flash_status: CALL SPI_init ;ensure known state of bus and s0 register
XOR s0, SPI_rom_cs ;select (Low) FLASH
OUTPUT s0, SPI_control_port
STORE s0, SPI_control_status ;preserve status
LOAD s2, 05 ;Read Status register instruction
CALL SPI_FLASH_tx_rx ;transmit instruction
CALL SPI_FLASH_tx_rx ;Receive status register information
XOR s0, SPI_rom_cs ;deselect (High) FLASH
OUTPUT s0, SPI_control_port
STORE s0, SPI_control_status ;preserve status
RETURN
;
;Set write enable mode in SPI FLASH memory (ST type M25P16)
;
;Transmits instruction 06hex.
;
set_spi_flash_WREN: CALL SPI_init ;ensure known state of bus and s0 register
XOR s0, SPI_rom_cs ;select (Low) FLASH
OUTPUT s0, SPI_control_port
STORE s0, SPI_control_status ;preserve status
LOAD s2, 06 ;Set write enable mode instruction
CALL SPI_FLASH_tx_rx ;transmit instruction
XOR s0, SPI_rom_cs ;deselect (High) FLASH
OUTPUT s0, SPI_control_port
STORE s0, SPI_control_status ;preserve status
RETURN
;
;Reset the write enable mode in SPI FLASH memory (ST type M25P16)
;
;Transmits instruction 04hex.
;
reset_spi_flash_WREN: CALL SPI_init ;ensure known state of bus and s0 register
XOR s0, SPI_rom_cs ;select (Low) FLASH
OUTPUT s0, SPI_control_port
STORE s0, SPI_control_status ;preserve status
LOAD s2, 04 ;Reset write enable mode instruction
CALL SPI_FLASH_tx_rx ;transmit instruction
XOR s0, SPI_rom_cs ;deselect (High) FLASH
OUTPUT s0, SPI_control_port
STORE s0, SPI_control_status ;preserve status
RETURN
;
;Read the identification ID from SPI FLASH memory (ST type M25P16)
;
;Transmits instruction 9Fhex and then reads the 3 byte response into [s9,s8,s7]
;
;response should be
; s9 = Manufacturer Identification = 20 hex
; s8 = Memory Type = 20 hex
; s7 = Memory Capacity = 15 hex
;
read_spi_flash_ID: CALL SPI_init ;ensure known state of bus and s0 register
XOR s0, SPI_rom_cs ;select (Low) FLASH
OUTPUT s0, SPI_control_port
STORE s0, SPI_control_status ;preserve status
LOAD s2, 9F ;Read ID instruction
CALL SPI_FLASH_tx_rx ;transmit instruction
CALL SPI_FLASH_tx_rx ;receive Manufacturer ID
LOAD s9, s2
CALL SPI_FLASH_tx_rx ;receive Memory Type
LOAD s8, s2
CALL SPI_FLASH_tx_rx ;receive Memory Capacity
LOAD s7, s2
XOR s0, SPI_rom_cs ;deselect (High) FLASH
OUTPUT s0, SPI_control_port
STORE s0, SPI_control_status ;preserve status
RETURN
;
;Read a single byte from the SPI FLASH memory (ST type M25P16)
;
;Transmits instruction 03hex followed by a 24-bit address which must be supplied in the
;register set [s9,s8,s7]. It then transmits a dummy byte to retrieve the memory data
;which is returned in register s2.
;
read_spi_byte: CALL SPI_init ;ensure known state of bus and s0 register
XOR s0, SPI_rom_cs ;select (Low) FLASH
OUTPUT s0, SPI_control_port
STORE s0, SPI_control_status ;preserve status
LOAD s2, 03 ;Read Data Bytes instruction
CALL SPI_FLASH_tx_rx ;transmit instruction
LOAD s2, s9 ;Transmit 24-bit address
CALL SPI_FLASH_tx_rx
LOAD s2, s8
CALL SPI_FLASH_tx_rx
LOAD s2, s7
CALL SPI_FLASH_tx_rx
CALL SPI_FLASH_tx_rx ;read data byte
XOR s0, SPI_rom_cs ;deselect (High) FLASH
OUTPUT s0, SPI_control_port
STORE s0, SPI_control_status ;preserve status
RETURN
;
;
;Erase a single sector from the SPI FLASH memory (ST type M25P16)
;
;Sets the WREN instruction and then transmits instruction D8 hex followed by a 24-bit
;address which must be supplied in the register set [s9,s8,s7]. The address must be
;at some location within the sector to be erased. A sector erase can take up to
;3 seconds to complete. The routine therefore reads the FLASH status and tests
;the write in progress (WIP) bit to test for completion
;
erase_spi_sector: CALL set_spi_flash_WREN ;set write enable mode
CALL SPI_init ;ensure known state of bus and s0 register
XOR s0, SPI_rom_cs ;select (Low) FLASH
OUTPUT s0, SPI_control_port
STORE s0, SPI_control_status ;preserve status
LOAD s2, D8 ;Sector erase mode
CALL SPI_FLASH_tx_rx ;transmit instruction
LOAD s2, s9 ;Transmit 24-bit address [s9,s8,s7].
CALL SPI_FLASH_tx_rx
LOAD s2, s8
CALL SPI_FLASH_tx_rx
LOAD s2, s7
CALL SPI_FLASH_tx_rx
XOR s0, SPI_rom_cs ;deselect (High) FLASH
OUTPUT s0, SPI_control_port
STORE s0, SPI_control_status ;preserve status
sector_erase_wait: CALL read_spi_flash_status ;test WIP bit until finished
TEST s2, 01
JUMP NZ, sector_erase_wait
RETURN
;
;
;
;Bulk erase the whole SPI FLASH memory (ST type M25P16)
;
;Sets the WREN instruction and then transmits instruction C7 hex.
;A bulk erase can take up to 40 seconds to complete. The routine therefore reads the
;FLASH status and tests the write in progress (WIP) bit to test for completion
;
bulk_erase_spi: CALL set_spi_flash_WREN ;set write enable mode
CALL SPI_init ;ensure known state of bus and s0 register
XOR s0, SPI_rom_cs ;select (Low) FLASH
OUTPUT s0, SPI_control_port
STORE s0, SPI_control_status ;preserve status
LOAD s2, C7 ;Sector erase mode
CALL SPI_FLASH_tx_rx ;transmit instruction
XOR s0, SPI_rom_cs ;deselect (High) FLASH
OUTPUT s0, SPI_control_port
STORE s0, SPI_control_status ;preserve status
bulk_erase_wait: CALL read_spi_flash_status ;test WIP bit until finished
TEST s2, 01
JUMP NZ, bulk_erase_wait
RETURN
;
;
;
;Open a page for programming.
;The 24-bit start address to be supplied in the register set [s9,s8,s7].
;Note that s7=00 hex for normal page boundaries but you could start at any address.
;Caution : Exceeding s7=FF hex will result in the roll over to 00 hex but without
;incrementing to the next page.
;
;Transmits instruction 02hex followed by the 24-bit start address.
;It is then ready to transmit data bytes using the s2 register and the SPI_FLASH_tx_rx
;subroutine. After transmitting bytes, close the page with the close_prog_page_spi
;routine.
;
open_prog_page_spi: CALL set_spi_flash_WREN ;set write enable mode
CALL SPI_init ;ensure known state of bus and s0 register
XOR s0, SPI_rom_cs ;select (Low) FLASH
OUTPUT s0, SPI_control_port
STORE s0, SPI_control_status ;preserve status
LOAD s2, 02 ;Page program mode
CALL SPI_FLASH_tx_rx ;transmit instruction
LOAD s2, s9 ;Transmit 24-bit address [s9,s8,s7].
CALL SPI_FLASH_tx_rx
LOAD s2, s8
CALL SPI_FLASH_tx_rx
LOAD s2, s7
CALL SPI_FLASH_tx_rx
RETURN
;
;
;This routine completes a page program operation started with
;open_prog_page_spi and data bytes sent with SPI_FLASH_tx_rx.
;
;A page program can take up to 5ms to complete. The routine therefore reads the
;FLASH status and tests the write in progress (WIP) bit to test for completion
;
;
close_prog_page_spi: FETCH s0, SPI_control_status ;read control status bits
XOR s0, SPI_rom_cs ;deselect (High) FLASH
OUTPUT s0, SPI_control_port
STORE s0, SPI_control_status ;preserve status
page_prog_wait: CALL read_spi_flash_status ;test WIP bit until finished
TEST s2, 01
JUMP NZ, page_prog_wait
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, 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.
;
;If the received character is an XOFF, then the routine will then wait
;for an XON to be received. This means that the rest of the program is held
;in suspense and therefore it can not transmit. Once an XON is received, it will
;again wait for a normal character before returning.
;
;NOTE: Characters between the XOFF and XON will be ignored in this version of the
;program!!!
;
;Interrupt is disabled during this routine to prevent a false situation. If the
;receiver half-full flag went High it should result in an interrupt transmitting
;an XOFF character. However, if this routine were able to read the receiver buffer
;at just about the same as the hardware detects the half-full flag, then it could
;think that an XON needs to be transmitted.
;
;
;Registers used s0 and UART_data
;
read_from_UART: DISABLE INTERRUPT
wait_Rx_character: INPUT s0, status_port ;test Rx_FIFO buffer
TEST s0, rx_data_present
JUMP NZ, read_character
JUMP wait_Rx_character
read_character: INPUT UART_data, UART_read_port ;read from FIFO
COMPARE UART_data, character_XOFF ;test for XOFF
JUMP Z, wait_XON
ENABLE INTERRUPT ;normal finish
RETURN
wait_XON: INPUT s0, status_port ;test Rx_FIFO buffer
TEST s0, rx_data_present
JUMP NZ, read_XON
JUMP wait_XON
read_XON: INPUT UART_data, UART_read_port ;read from FIFO
COMPARE UART_data, character_XON ;test for XON
JUMP Z, wait_Rx_character ;now wait for normal character
JUMP wait_XON ;continue to wait for XON
;
;
;
;Transmit one character to the UART
;
;Character supplied in register called 'UART_data'.
;
;The routine first tests the transmit FIFO buffer is empty.
;If the FIFO currently has any data, the routine waits until it is empty.
;Ultimately this means that only one character is sent at a time which
;could be important if the PC at the other end of the link transmits
;an XOFF and needs the flow of data to terminate as soon as possible.
;
;Registers used s0
;
send_to_UART: INPUT s0, status_port ;test Tx_FIFO buffer
TEST s0, tx_data_present
JUMP Z, UART_write
JUMP send_to_UART
UART_write: OUTPUT UART_data, UART_write_port
RETURN
;
;Convert value provided in register s0 into ASCII characters
;
;The value provided must in the range 0 to 99 and will be converted into
;two ASCII characters.
; The number of 'tens' will be represented by an ASCII character returned in register s1.
; The number of 'units' will be represented by an ASCII character returned in register s0.
;
;The ASCII representations of '0' to '9' are 30 to 39 hexadecimal which is simply 30 hex added to
;the actual decimal value.
;
;Registers used s0 and s1.
;
decimal_to_ASCII: LOAD s1, 30 ;load 'tens' counter with ASCII for '0'
test_for_ten: ADD s1, 01 ;increment 'tens' value
SUB s0, 0A ;try to subtract 10 from the supplied value
JUMP NC, test_for_ten ;repeat if subtraction was possible without underflow.
SUB s1, 01 ;'tens' value one less ten due to underflow
ADD s0, 3A ;restore units value (the remainder) and convert to ASCII
RETURN
;
;
;
;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 character '0' to '9' to numerical value in range 0 to 9
;
;The character supplied in register s0. If the character is in the
;range '0' to '9', it is converted to the equivalent decimal value.
;Characters not in the range '0' to '9' are signified by the return
;with the CARRY flag set.
;
;Registers used s0.
;
onechar_to_value: ADD s0, C6 ;reject character codes above '9' (39 hex)
RETURN C ;carry flag is set
SUB s0, F6 ;reject character codes below '0' (30 hex)
RETURN ;carry is set if value not in range
;
;
;Determine the numerical value of a two character decimal string held in
;scratch pad memory such the result is in the range 0 to 99 (00 to 63 hex).
;
;The string must be stored in two consecutive memory locations and the
;location of the first (tens) character supplied in the s1 register.
;The result is provided in register s2. Strings not using characters in the
;range '0' to '9' are signified by the return with the CARRY flag set.
;
;Registers used s0, s1 and s2.
;
twochar_to_value: FETCH s0, (s1) ;read 'tens' character
CALL onechar_to_value ;convert to numerical value
RETURN C ;bad character - CARRY set
LOAD s2, s0
SL0 s2 ;multiply 'tens' value by 10 (0A hex)
SL0 s2
ADD s2, s0
SL0 s2
ADD s1, 01 ;read 'units' character
FETCH s0, (s1)
CALL onechar_to_value ;convert to numerical value
RETURN C ;bad character - CARRY set
ADD s2, s0 ;add units to result and clear CARRY flag
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
;
;
;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
;
;
;
;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
;
;
;**************************************************************************************
;Text messages
;**************************************************************************************
;
;
;Send 'PicoBlaze SPI FLASH Programmer' 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_S
CALL send_to_UART
LOAD UART_data, character_P
CALL send_to_UART
LOAD UART_data, character_I
CALL send_to_UART
CALL send_space
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
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_a
CALL send_to_UART
LOAD UART_data, character_m
CALL send_to_UART
LOAD UART_data, character_m
CALL send_to_UART
LOAD UART_data, character_e
CALL send_to_UART
LOAD UART_data, character_r
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 'Waiting_MCS_file' string to the UART
;
send_Waiting_MCS_file: LOAD UART_data, character_W
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_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
LOAD UART_data, character_f
CALL send_to_UART
LOAD UART_data, character_o
CALL send_to_UART
LOAD UART_data, character_r
CALL send_to_UART
send_MCS_file: CALL send_space
LOAD UART_data, character_M
CALL send_to_UART
LOAD UART_data, character_C
CALL send_to_UART
LOAD UART_data, character_S
CALL send_to_UART
CALL send_space
LOAD UART_data, character_F
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
CALL send_CR
RETURN
;
;
;Send 'Erase in progress' string to the UART
;
send_Erase_in_progress: CALL send_Erase
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 '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 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 menu to the UART
;
send_Menu: CALL send_CR
LOAD UART_data, character_E
CALL send_to_UART
LOAD UART_data, character_minus
CALL send_to_UART
CALL send_Erase
LOAD UART_data, character_a
CALL send_to_UART
LOAD UART_data, character_l
CALL send_to_UART
CALL send_to_UART
CALL send_CR
LOAD UART_data, character_S
CALL send_to_UART
LOAD UART_data, character_minus
CALL send_to_UART
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_t
CALL send_to_UART
LOAD UART_data, character_o
CALL send_to_UART
LOAD UART_data, character_r
CALL send_to_UART
CALL send_space
CALL send_Erase
CALL send_CR
LOAD UART_data, character_P
CALL send_to_UART
LOAD UART_data, character_minus
CALL send_to_UART
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_a
CALL send_to_UART
LOAD UART_data, character_m
CALL send_to_UART
CALL send_MCS_file
LOAD UART_data, character_R
CALL send_to_UART
LOAD UART_data, character_minus
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_a
CALL send_to_UART
LOAD UART_data, character_d
CALL send_to_UART
CALL send_space
CALL send_page
CALL send_CR
LOAD UART_data, character_I
CALL send_to_UART
LOAD UART_data, character_minus
CALL send_to_UART
LOAD UART_data, character_D
CALL send_to_UART
LOAD UART_data, character_e
CALL send_to_UART
LOAD UART_data, character_v
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_e
CALL send_to_UART
CALL send_space
CALL send_ID
CALL send_CR
LOAD UART_data, character_H
CALL send_to_UART
LOAD UART_data, character_minus
CALL send_to_UART
LOAD UART_data, character_H
CALL send_to_UART
LOAD UART_data, character_e
CALL send_to_UART
LOAD UART_data, character_l
CALL send_to_UART
LOAD UART_data, character_p
CALL send_to_UART
CALL send_CR
RETURN
;
;
;Send 'page' to the UART
;
send_page: LOAD UART_data, character_p
CALL send_to_UART
LOAD UART_data, character_a
CALL send_to_UART
LOAD UART_data, character_g
CALL send_to_UART
LOAD UART_data, character_e
CALL send_to_UART
RETURN
;
;Send 'ID' to the UART
;
send_ID: LOAD UART_data, character_I
CALL send_to_UART
LOAD UART_data, character_D
CALL send_to_UART
RETURN
;
;
;Send 'Confirm Erase (Y/n) ' to the UART
;
send_Confirm: CALL send_CR
LOAD UART_data, character_C
CALL send_to_UART
LOAD UART_data, character_o
CALL send_to_UART
LOAD UART_data, character_n
CALL send_to_UART
LOAD UART_data, character_f
CALL send_to_UART
LOAD UART_data, character_i
CALL send_to_UART
LOAD UART_data, character_r
CALL send_to_UART
LOAD UART_data, character_m
CALL send_to_UART
CALL send_space
CALL send_Erase
LOAD UART_data, character_open
CALL send_to_UART
LOAD UART_data, character_Y
CALL send_to_UART
LOAD UART_data, character_divide
CALL send_to_UART
LOAD UART_data, character_n
CALL send_to_UART
LOAD UART_data, character_close
CALL send_to_UART
CALL send_space
RETURN
;
;
;Send 'Abort' to the UART
;
send_Abort: CALL send_CR
LOAD UART_data, character_A
CALL send_to_UART
LOAD UART_data, character_b
CALL send_to_UART
LOAD UART_data, character_o
CALL send_to_UART
LOAD UART_data, character_r
CALL send_to_UART
LOAD UART_data, character_t
CALL send_to_UART
CALL send_CR
RETURN
;
;Send 'page address' to the UART
;
send_page_address: CALL send_CR
CALL send_page
CALL send_space
LOAD UART_data, character_a
CALL send_to_UART
LOAD UART_data, character_d
CALL send_to_UART
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
LOAD UART_data, character_equals
CALL send_to_UART
RETURN
;
;
;**************************************************************************************
;Interrupt Service Routine (ISR)
;**************************************************************************************
;
;An interrupt occurs whenever the status of the UART receiver FIFO 'half_full' flag
;changes.
;
;A change from Low to High means that the buffer is becoming full and therefore
;an XOFF character must be transmitted.
;
;A change from High to Low means that the buffer is starting to empty and therefore
;an XON character can be transmitted to restart the flow of new characters.
;
;
ADDRESS 3F5 ;place at end of memory to keep separate
ISR: STORE s0, ISR_preserve_s0 ;preserve register contents
INPUT s0, status_port ;test 'half_full' status of receiver buffer.
TEST s0, rx_half_full
JUMP Z, isr_send_xon
LOAD s0, character_XOFF
JUMP isr_send_character
isr_send_xon: LOAD s0, character_XON
isr_send_character: OUTPUT s0, UART_write_port
FETCH s0, ISR_preserve_s0 ;restore register contents
RETURNI ENABLE
;
;
;**************************************************************************************
;Interrupt Vector
;**************************************************************************************
;
ADDRESS 3FF
JUMP ISR
;
;