URL
https://opencores.org/ocsvn/copyblaze/copyblaze/trunk
Subversion Repositories copyblaze
[/] [copyblaze/] [trunk/] [copyblaze/] [sw/] [code/] [kcpsm/] [uclock/] [uclock.psm] - Rev 70
Go to most recent revision | Compare with Previous | Blame | View Log
;KCPSM3 Program - Real Time Clock with UART communication.
;
;Ken Chapman - Xilinx Ltd - October 2003
;
;
;Port definitions
;
CONSTANT UART_status_port, 00 ;UART status input
CONSTANT tx_half_full, 01 ; Transmitter half full - bit0
CONSTANT tx_full, 02 ; FIFO full - bit1
CONSTANT rx_half_full, 04 ; Receiver half full - bit2
CONSTANT rx_full, 08 ; FIFO full - bit3
CONSTANT rx_data_present, 10 ; data present - bit4
;
CONSTANT UART_read_port, 01 ;UART Rx data input
;
CONSTANT UART_write_port, 01 ;UART Tx data output
;
CONSTANT alarm_port, 00 ;Alarm output
CONSTANT alarm_control, 01 ; bit0
;
;Special Register usage
;
NAMEREG sF, UART_data ;used to pass data to and from the UART
;
NAMEREG sE, store_pointer ;used to pass location of data in scratch pad memory
;
;Two registers to form a 16-bit counter used to count
;interrupt pulses generated at 1us intervals.
;
NAMEREG sD, int_counter_lsb ;lower 8-bits
NAMEREG sC, int_counter_msb ;upper 8-bits
;
;
;Scratch Pad Memory Locations
;
;
CONSTANT us_time_stamp_lsb, 00 ;16-bit micro-second time stamp
CONSTANT us_time_stamp_msb, 01
;
CONSTANT us_time_lsb, 02 ;16-bit micro-second real time value
CONSTANT us_time_msb, 03
;
CONSTANT ms_time_lsb, 04 ;16-bit milli-second real time value
CONSTANT ms_time_msb, 05
;
CONSTANT real_time_hours, 06 ;Current clock time
CONSTANT real_time_minutes, 07
CONSTANT real_time_seconds, 08
;
CONSTANT alarm_time_hours, 09 ;Alarm time
CONSTANT alarm_time_minutes, 0A
CONSTANT alarm_time_seconds, 0B
;
CONSTANT alarm_status, 0C ;Alarm status
CONSTANT alarm_active, 01 ; bit0 - Alarm is active
CONSTANT alarm_armed, 02 ; bit1 - Alarm is armed
;
CONSTANT time_preserve0, 10 ;storage for protection of registers
CONSTANT time_preserve1, 11 ;used by the real time clock routine.
CONSTANT time_preserve2, 12
CONSTANT time_preserve3, 13
CONSTANT time_preserve4, 14
CONSTANT time_preserve5, 15
;
;UART character strings will be stored in scratch pad memory ending in carriage return.
;A string can be up to 16 characters with the start location defined by this constant.
;
CONSTANT string_start, 20
;
;
;Initialise the system
;
;
cold_start: LOAD s0, 00 ;clear all time values
STORE s0, us_time_stamp_lsb
STORE s0, us_time_stamp_msb
STORE s0, us_time_lsb
STORE s0, us_time_msb
STORE s0, ms_time_lsb
STORE s0, ms_time_msb
STORE s0, real_time_hours
STORE s0, real_time_minutes
STORE s0, real_time_seconds
STORE s0, alarm_time_hours
STORE s0, alarm_time_minutes
STORE s0, alarm_time_seconds
STORE s0, alarm_status ;clear and disable alarm
CALL alarm_drive ;turn off alarm control output port
LOAD int_counter_lsb, 00 ;clear 'us' interrupt counter
LOAD int_counter_msb, 00
ENABLE INTERRUPT ;enable the 1us interrupts
;
;
;Start of the main program loop.
;
;A prompt is transmitted to the UART transmitter and then
;a command can be entered and interpreted.
;
;
prompt_input: CALL send_prompt ;Prompt 'KCPSM3>'
CALL receive_string ;obtain input string and maintain the time
;
;
;Parse the string and perform actions as required
;
;
;
LOAD s1, string_start
CALL fetch_char_from_memory
COMPARE s0, character_CR ;carriage return does nothing
JUMP Z, prompt_input
COMPARE s0, character_T ;start of 'TIME' command?
JUMP Z, test_for_TIME
COMPARE s0, character_A ;start of 'ALARM' command?
JUMP Z, test_for_ALARM
;
;trap other command starts here
;
bad_input_command: CALL send_Syntax_Error ;no valid command
JUMP Z, prompt_input
;
;
test_for_TIME: CALL fetch_char_from_memory
COMPARE s0, character_I ;test for rest of 'TIME'
JUMP NZ, bad_input_command
CALL fetch_char_from_memory
COMPARE s0, character_M
JUMP NZ, bad_input_command
CALL fetch_char_from_memory
COMPARE s0, character_E
JUMP NZ, bad_input_command
;now have a valid TIME command to process
CALL fetch_char_from_memory
COMPARE s0, character_CR ;carriage return means display time
JUMP NZ, set_time_command
CALL transmit_time ;transmit time to UART
JUMP prompt_input
set_time_command: COMPARE s0, character_space
JUMP NZ, bad_input_command
CALL test_time_string ;interpret 'hh:mm:ss' string
JUMP C, prompt_input ;test for invalid input
STORE s6, real_time_hours ;set new time into clock
STORE s5, real_time_minutes
STORE s4, real_time_seconds
STORE s0, ms_time_lsb ;clear 'ms' counter (s0=00)
STORE s0, ms_time_msb
CALL transmit_time ;transmit new time to UART
JUMP prompt_input
;
;
test_for_ALARM: CALL fetch_char_from_memory
COMPARE s0, character_L ;test for rest of 'ALARM'
JUMP NZ, bad_input_command
CALL fetch_char_from_memory
COMPARE s0, character_A
JUMP NZ, bad_input_command
CALL fetch_char_from_memory
COMPARE s0, character_R
JUMP NZ, bad_input_command
CALL fetch_char_from_memory
COMPARE s0, character_M
JUMP NZ, bad_input_command
;now have a valid ALARM command to process
CALL fetch_char_from_memory
COMPARE s0, character_CR ;carriage return means display alarm time
JUMP NZ, set_alarm_command
CALL transmit_alarm_time ;transmit time to UART
JUMP prompt_input
set_alarm_command: COMPARE s0, character_space ;test for ON or OFF command
JUMP NZ, bad_input_command
CALL fetch_char_from_memory
COMPARE s0, character_O
JUMP Z, set_alarm_on_off
SUB s1, 01 ;move memory pointer back to first character of 'hh:mm:ss' string
CALL test_time_string ;interpret 'hh:mm:ss' string
JUMP C, prompt_input ;test for invalid input
STORE s6, alarm_time_hours ;set new time into clock
STORE s5, alarm_time_minutes
STORE s4, alarm_time_seconds
CALL transmit_alarm_time ;transmit new alarm time and status
JUMP prompt_input
set_alarm_on_off: CALL fetch_char_from_memory
COMPARE s0, character_N ;test for 'ON'
JUMP NZ, test_OFF
CALL fetch_char_from_memory
COMPARE s0, character_CR
JUMP NZ, bad_input_command
FETCH s0, alarm_status ;turn alarm on
OR s0, alarm_armed
STORE s0, alarm_status
CALL transmit_alarm_time ;transmit alarm time and status
JUMP prompt_input
test_OFF: COMPARE s0, character_F ;test for for 'OFF'
JUMP NZ, bad_input_command
CALL fetch_char_from_memory
COMPARE s0, character_F
JUMP NZ, bad_input_command
CALL fetch_char_from_memory
COMPARE s0, character_CR
JUMP NZ, bad_input_command
LOAD s0, 00 ;turn alarm off and stop an active alarm
STORE s0, alarm_status
CALL alarm_drive ;turn off alarm
CALL transmit_alarm_time ;transmit alarm time and status
JUMP prompt_input
;
;
;
;
;Read an 'hh:mm:ss' time string and provide new values.
;
;The string must be provided in successive scratch pad memory locations
;with the s1 register containing the location of the first character.
;
;A correct time specification will result in the return of new values
;as follows:-
;
; s6 = hours
; s5 = minutes
; s4 = seconds
;
;If the syntax is incorrect or values are not in the correct ranges an
;'Invalid Time' message will be transmitted and the CARRY flag will be set
;
;Registers used s0, s1, s6, s5 and s4
;
test_time_string: CALL 2char_to_value ;obtain hours value
JUMP C, invalid_time ;test for non-decimal characters
LOAD s6, s2 ;remember hours
ADD s1, 01 ;increment memory pointer past hours
CALL fetch_char_from_memory
COMPARE s0, character_colon ;test for colon
JUMP NZ, invalid_time
CALL 2char_to_value ;obtain minutes value
JUMP C, invalid_time ;test for non-decimal characters
LOAD s5, s2 ;remember minutes
ADD s1, 01 ;increment memory pointer past minutes
CALL fetch_char_from_memory
COMPARE s0, character_colon ;test for colon
JUMP NZ, invalid_time
CALL 2char_to_value ;obtain seconds value
JUMP C, invalid_time ;test for non-decimal characters
LOAD s4, s2 ;remember minutes
ADD s1, 01 ;increment memory pointer past seconds
CALL fetch_char_from_memory
COMPARE s0, character_CR ;finish with carriage return
JUMP NZ, invalid_time
;Have values for hh:mm:ss but need to test if each is valid range.
COMPARE s6, hours_in_a_day
JUMP NC, invalid_time
COMPARE s5, minutes_in_an_hour
JUMP NC, invalid_time
COMPARE s4, seconds_in_a_minute
JUMP NC, invalid_time
LOAD s0, 00
SR0 s0 ;reset CARRY flag (with s0=0)
RETURN ;time string was OK
invalid_time: CALL send_Invalid
CALL send_space
CALL send_Time
LOAD s0, 01
SR0 s0 ;set CARRY flag
RETURN ;time string was bad
;
;
;Fetch character from memory, convert to upper case
;and increment memory pointer.
;
;The memory pointer is provided in register s1.
;The character obtained is returned in register s0.
;
;Registers used s0 and s1.
;
fetch_char_from_memory: FETCH s0, (s1) ;read character
CALL upper_case ;convert to upper case
ADD s1, 01 ;increment memory pointer
RETURN
;
;
;
;Read one character from the UART
;
;Character read will be returned in a register called 'UART_data' and will be
;echoed to the UART transmitter.
;
;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 includes a call to the
;subroutine which updates the real time clock.
;
;Registers used s0 and UART_data
;
read_from_UART: INPUT s0, UART_status_port ;test Rx_FIFO buffer
TEST s0, rx_data_present
JUMP NZ, read_character
CALL update_time ;Perform useful operation whilst waiting
JUMP read_from_UART
read_character: INPUT UART_data, UART_read_port ;read from FIFO
CALL send_to_UART ;echo received character
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, the routine waits until there is space which could
;be as long as it takes to transmit one complete character.
;
; Baud Rate Time per Character (10 bits)
; 9600 1,024us
; 19200 521us
; 38400 260us
; 57600 174us
; 115200 87us
;
;Since this is a relatively long duration, the wait loop includes a
;call to the subroutine which updates the real time clock.
;
;Registers used s0
;
send_to_UART: INPUT s0, UART_status_port ;test Tx_FIFO buffer
TEST s0, tx_full
JUMP Z, UART_write
CALL update_time ;Perform useful operation whilst waiting
JUMP send_to_UART
UART_write: OUTPUT UART_data, UART_write_port
RETURN
;
;
;
;
;Alarm output
;
;Uses the alarm status scratch pad memory to set or reset the alarm
;control bit on the alarm output port.
;
;Registers used s0
;
alarm_drive: FETCH s0, alarm_status ;read status
AND s0, alarm_active ;isolate bit0
OUTPUT s0, alarm_port
RETURN
;
;
;
;
;
;Transmit the time to the UART port in the format hh:mm:ss and end
;with a carriage return.
;
;The time to converted must be stored in 3 scratch pad memory locations as
;defined below. A register named 'store_pointer' must provide the address of
;first location.
;
; Address Data
;
; store_pointer ----> hours
; store_pointer + 1 ----> minutes
; store_pointer + 1 ----> seconds
;
;The routine first converts the time into an ASCII string stored in scratch
;pad memory starting at a location specified by a constant named 'string_start'.
;The string will then be transmitted.
;
;Registers used s0, s1, s2, 'store_pointer' and 'UART_data'.
;
transmit_time: LOAD store_pointer, real_time_hours ;locate current time in memory
CALL time_to_ASCII
CALL transmit_string
RETURN
;
;
;Transmit the alarm time and status to the UART port in the format hh:mm:ss and
;ending with carriage return.
;
;The alarm time to converted must be stored in 3 scratch pad memory locations as
;defined below. A register named 'store_pointer' must provide the address of
;first location.
;
; Address Data
;
; store_pointer ----> hours
; store_pointer + 1 ----> minutes
; store_pointer + 1 ----> seconds
;
;The routine first converts the time into an ASCII string stored in scratch
;pad memory starting at a location specified by a constant named 'string_start'.
;The string will then be transmitted.
;
;Registers used s0, s1, s2, 'store_pointer' and 'UART_data'.
;
transmit_alarm_time: LOAD store_pointer, alarm_time_hours ;locate alarm time in memory
CALL time_to_ASCII
CALL transmit_string
CALL send_Alarm
CALL send_space
FETCH s0, alarm_status ;read alarm status
TEST s0, alarm_active ;test for active
JUMP Z, test_armed
CALL send_Active
RETURN
test_armed: TEST s0, alarm_armed ;test for on
JUMP Z, alarm_is_off
CALL send_ON
RETURN
alarm_is_off: CALL send_OFF
RETURN
;
;
;Transmit ASCII string to UART
;
;An ASCII string must be provided in scratch pad memory commencing at the
;location specified by a constant named 'string_start'. The string must
;end with a carriage return (0D).
;
;Registers used s1 and 'UART_data'.
; s0 is then used in subroutine 'send_to_UART'
;
transmit_string: LOAD s1, string_start ;locate start of string
next_char_tx: FETCH UART_data, (s1) ;read character from memory
CALL send_to_UART ;transmit character
COMPARE UART_data, character_CR ;test for last character
RETURN Z
ADD s1, 01 ;move to next character
JUMP next_char_tx
;
;
;Receive ASCII string from UART
;
;An ASCII string will be read from the UART and stored in scratch pad memory
;commencing at the location specified by a constant named 'string_start'.
;The string will will have a maximum length of 16 characters including a
;carriage return (0D) denoting the end of the string.
;
;As each character is read, it is echoed to the UART transmitter.
;Some minor editing is supported using backspace (BS=08) which is used
;to adjust what is stored in scratch pad memory and adjust the display
;on the terminal screen using characters sent to the UART transmitter.
;
;A test is made for the receiver FIFO becoming full. A full status is treated as
;a potential error situation and will result in a 'Overflow Error' message being
;transmitted to the UART, the receiver FIFO being purged of all data and an
;empty string being stored (carriage return at first location).
;
;Registers used s0, s1, s2 and 'UART_data'.
;
receive_string: LOAD s1, string_start ;locate start of string
LOAD s2, s1 ;compute 16 character address
ADD s2, 10
receive_full_test: INPUT s0, UART_status_port ;test Rx_FIFO buffer for full
TEST s0, rx_full
JUMP NZ, read_error
CALL read_from_UART ;obtain and echo character
STORE UART_data, (s1) ;write to memory
COMPARE UART_data, character_CR ;test for end of string
RETURN Z
COMPARE UART_data, character_BS ;test for back space
JUMP Z, BS_edit
ADD s1, 01 ;increment memory pointer
COMPARE s1, s2 ;test for pointer exceeding 16 characters
JUMP NZ, receive_full_test ;next character
CALL send_backspace ;hold end of string position on terminal display
BS_edit: SUB s1, 01 ;memory pointer back one
COMPARE s1, string_start ;test for under flow
JUMP C, string_start_again
CALL send_space ;clear character at current position
CALL send_backspace ;position cursor
JUMP receive_full_test ;next character
string_start_again: CALL send_greater_than ;restore '>' at prompt
JUMP receive_string ;begin again
;Receiver buffer overflow condition
read_error: CALL send_CR ;Transmit error message
STORE UART_data, string_start ;empty string in memory (start with CR)
CALL send_Overflow_Error
CALL send_CR
clear_UART_Rx_loop: INPUT s0, UART_status_port ;test Rx_FIFO buffer for data
TEST s0, rx_data_present
RETURN Z ;finish when buffer is empty
INPUT UART_data, UART_read_port ;read from FIFO and ignore
JUMP clear_UART_Rx_loop
;
;
;
;Send Carriage Return to the UART
;
send_CR: LOAD UART_data, character_CR
CALL send_to_UART
RETURN
;
;
;
;Send a space to the UART
;
send_space: LOAD UART_data, character_space
CALL send_to_UART
RETURN
;
;
;Send a back space to the UART
;
send_backspace: LOAD UART_data, character_BS
CALL send_to_UART
RETURN
;
;Send 'Syntax Error' to the UART
;
send_Syntax_Error: LOAD UART_data, character_S
CALL send_to_UART
LOAD UART_data, character_y
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_a
CALL send_to_UART
LOAD UART_data, character_x
CALL send_to_UART
JUMP send_space_Error
;
;Send 'Overflow Error' to the UART
;
send_Overflow_Error: LOAD UART_data, character_O
CALL send_to_UART
LOAD UART_data, character_v
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_f
CALL send_to_UART
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
send_space_Error: CALL send_space
;
;Send 'Error' to the UART
;
send_Error: LOAD UART_data, character_E
CALL send_to_UART
LOAD UART_data, character_r
CALL send_to_UART
CALL send_to_UART
LOAD UART_data, character_o
CALL send_to_UART
LOAD UART_data, character_r
CALL send_to_UART
RETURN
;
;Send 'KCPSM3>' prompt to the UART
;
send_prompt: CALL send_CR ;start new line
LOAD UART_data, character_K
CALL send_to_UART
LOAD UART_data, character_C
CALL send_to_UART
LOAD UART_data, character_P
CALL send_to_UART
LOAD UART_data, character_S
CALL send_to_UART
LOAD UART_data, character_M
CALL send_to_UART
LOAD UART_data, character_3
CALL send_to_UART
;
;Send '>' character to the UART
;
send_greater_than: LOAD UART_data, character_greater_than
CALL send_to_UART
RETURN
;
;Send 'Invalid' string to the UART
;
send_Invalid: LOAD UART_data, character_I
CALL send_to_UART
LOAD UART_data, character_n
CALL send_to_UART
LOAD UART_data, character_v
CALL send_to_UART
LOAD UART_data, character_a
CALL send_to_UART
LOAD UART_data, character_l
CALL send_to_UART
LOAD UART_data, character_i
CALL send_to_UART
LOAD UART_data, character_d
CALL send_to_UART
RETURN
;
;Send 'Time' string to the UART
;
send_Time: LOAD UART_data, character_T
CALL send_to_UART
LOAD UART_data, character_i
CALL send_to_UART
LOAD UART_data, character_m
CALL send_to_UART
LOAD UART_data, character_e
CALL send_to_UART
RETURN
;
;Send 'Alarm' string to the UART
;
send_Alarm: LOAD UART_data, character_A
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_r
CALL send_to_UART
LOAD UART_data, character_m
CALL send_to_UART
RETURN
;
;Send 'OFF' string to the UART
;
send_OFF: LOAD UART_data, character_O
CALL send_to_UART
LOAD UART_data, character_F
CALL send_to_UART
CALL send_to_UART
RETURN
;
;Send 'ON' string to the UART
;
send_ON: LOAD UART_data, character_O
CALL send_to_UART
LOAD UART_data, character_N
CALL send_to_UART
RETURN
;
;Send 'Active' string to the UART
;
send_Active: LOAD UART_data, character_A
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_i
CALL send_to_UART
LOAD UART_data, character_v
CALL send_to_UART
LOAD UART_data, character_e
CALL send_to_UART
RETURN
;
;
;Convert time to ASCII string in scratch pad memory.
;
;The time to converted must be stored in 3 scratch pad memory locations as
;defined below. A register named 'store_pointer' must provide the address of
;first location.
;
; Address Data
;
; store_pointer ----> hours
; store_pointer + 1 ----> minutes
; store_pointer + 1 ----> seconds
;
;The resulting ASCII string will be stored in scratch pad memory starting at
;a location specified by a constant named 'string_start'. The string will
;take the format hh:mm:ss and end with a carriage return.
;
;Registers used s0, s1, s2 and 'store_pointer'.
;
time_to_ASCII: LOAD s2, string_start ;location for string
FETCH s0, (store_pointer) ;read hours value
CALL decimal_to_ASCII ;convert to ASCII
STORE s1, (s2) ;write hours to string
ADD s2, 01
STORE s0, (s2)
ADD s2, 01
LOAD s0, character_colon ;write ':' to string
STORE s0, (s2)
ADD s2, 01
ADD store_pointer, 01 ;move to minutes
FETCH s0, (store_pointer) ;read minutes value
CALL decimal_to_ASCII ;convert to ASCII
STORE s1, (s2) ;write minutes to string
ADD s2, 01
STORE s0, (s2)
ADD s2, 01
LOAD s0, character_colon ;write ':' to string
STORE s0, (s2)
ADD s2, 01
ADD store_pointer, 01 ;move to seconds
FETCH s0, (store_pointer) ;read seconds value
CALL decimal_to_ASCII ;convert to ASCII
STORE s1, (s2) ;write seconds to string
ADD s2, 01
STORE s0, (s2)
ADD s2, 01
LOAD s0, character_CR ;finish string with carriage return
STORE s0, (s2)
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 representd by an ASCII character returned in register s1.
; The number of 'units' will be representd 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
;
;
;
;
;Real Time Clock
;
;Uses the 1us interrupt counter [int_counter_msb,int_counter_lsb] to determine how many
;micro-seconds have elapsed since the last update. This allows for just over 65ms between
;updates. Complete multiples of 1000us are used to update a 16-bit milli-second counter held
;in scratch pad memory locations [ms_time_stamp_msb,ms_time_stamp_msb] which in turn
;is used to update the real time hours, minutes and seconds clock held in scratch pad
;memory locations 'real_time_hours', 'real_time_minutes' and 'real_time_seconds'.
;
;The routine uses default register names s0,s1,s2,s3,s4,s5. These are preserved in scratch pad
;memory during the routine and restored before returning.
;
;Useful constants for real time clock operations
;
CONSTANT count_1000_lsb, E8 ;lower 8-bits of 1000 count value
CONSTANT count_1000_msb, 03 ;upper 8-bits of 1000 count value
CONSTANT hours_in_a_day, 18 ;24 hours in a day
CONSTANT minutes_in_an_hour, 3C ;60 minutes in an hour
CONSTANT seconds_in_a_minute, 3C ;60 seconds in a minute
;
update_time: STORE s0, time_preserve0 ;preserve contents of registers used during routine
STORE s1, time_preserve1
STORE s2, time_preserve2
STORE s3, time_preserve3
STORE s4, time_preserve4
STORE s5, time_preserve5
;
FETCH s2, us_time_stamp_lsb ;read the previous 'us' time stamp into [s3,s2]
FETCH s3, us_time_stamp_msb
DISABLE INTERRUPT ;Read and store current 'us' time stamp provided by the interrupt
STORE int_counter_lsb, us_time_stamp_lsb ;counter. Interrupts are disabled to ensure that both bytes relate
STORE int_counter_msb, us_time_stamp_msb ;to the same count value.
ENABLE INTERRUPT
FETCH s4, us_time_stamp_lsb ;read the new 'us' time stamp in [s5,s4]
FETCH s5, us_time_stamp_msb ;
SUB s4, s2 ;calculate 'us' time difference [s5,s4] = [s5,s4] - [s3,s2]
SUBCY s5, s3 ; (This works correctly even if counter has rolled over)
FETCH s2, us_time_lsb ;read current 'us' time into [s3,s2]
FETCH s3, us_time_msb
ADD s2, s4 ;add on the elapsed 'us' value [s3,s2] = [s3,s2] + [s5,s4]
ADDCY s3, s5
;determine how many 1000us (1ms) units there are (if any) in current 'us' time
LOAD s0, 00 ;reset 'ms' counter
test_1000us: SUB s2, count_1000_lsb ;subtract 1000 from [s3,s2]
SUBCY s3, count_1000_msb
JUMP C, store_us_time ;Carry indicates [s3,s2] was less than 1000us
ADD s0, 01 ;increment 'ms' elapsed because [s3,s2] was more or equal to 1000us
JUMP test_1000us ;repeat to see if more than 1ms has elapsed
store_us_time: ADD s2, count_1000_lsb ;add 1000 to restore 'us' value
ADDCY s3, count_1000_msb
STORE s2, us_time_lsb ;store the current value of 'us'
STORE s3, us_time_msb
;s0 holds the number of 'ms' elapsed since last update (if any).
FETCH s2, ms_time_lsb ;read current 'ms' time into [s3,s2]
FETCH s3, ms_time_msb
ADD s2, s0 ;add on the elapsed 'ms' value [s3,s2] = [s3,s2] + s0
ADDCY s3, 00
;determine if there are now more than 1000ms to form 1 second.
LOAD s0, 00 ;reset 'second' counter
SUB s2, count_1000_lsb ;subtract 1000 from [s3,s2]
SUBCY s3, count_1000_msb
JUMP C, restore_ms_time ;Carry indicates [s3,s2] was less than 1000ms
ADD s0, 01 ;increment 'second' elapsed because [s3,s2] was more or equal to 1000ms
JUMP store_ms_time ;new value of 'ms' is remainder of subtraction
restore_ms_time: ADD s2, count_1000_lsb ;add 1000 to restore 'ms' value
ADDCY s3, count_1000_msb
store_ms_time: STORE s2, ms_time_lsb ;store the current value of 'ms'
STORE s3, ms_time_msb
;s0 currently determines if one second needs to be added to the hh:mm:ss clock time
FETCH s1, real_time_seconds ;read seconds
ADD s1, s0 ;add one second if required by s0
COMPARE s1, seconds_in_a_minute ;test for 1 minute
JUMP Z, inc_minutes
STORE s1, real_time_seconds ;store updated seconds
JUMP time_update_complete
inc_minutes: LOAD s1, 00 ;seconds become zero
STORE s1, real_time_seconds
FETCH s1, real_time_minutes ;read minutes
ADD s1, 01 ;increment minutes
COMPARE s1, minutes_in_an_hour ;test for 1 hour
JUMP Z, inc_hours
STORE s1, real_time_minutes ;store updated minutes
JUMP time_update_complete
inc_hours: LOAD s1, 00 ;minutes become zero
STORE s1, real_time_minutes
FETCH s1, real_time_hours ;read hours
ADD s1, 01 ;increment hours
COMPARE s1, hours_in_a_day ;test for 24 hours
JUMP Z, reset_hours
STORE s1, real_time_hours ;store updated hours
JUMP time_update_complete
reset_hours: LOAD s1, 00 ;hours become zero
STORE s1, real_time_hours
;
;With the time updated, there is then a test for time=alarm time
;
time_update_complete: FETCH s0, real_time_hours
FETCH s1, alarm_time_hours ;compare hours
COMPARE s0, s1
JUMP NZ, finish_update
FETCH s0, real_time_minutes ;compare minutes
FETCH s1, alarm_time_minutes
COMPARE s0, s1
JUMP NZ, finish_update
FETCH s0, real_time_seconds ;compare seconds
FETCH s1, alarm_time_seconds
COMPARE s0, s1
JUMP NZ, finish_update
FETCH s0, alarm_status ;test if alarm is turned on
TEST s0, alarm_armed
JUMP Z, finish_update ;alarm was off
OR s0, alarm_active ;activate alarm
STORE s0, alarm_status
CALL alarm_drive
finish_update: FETCH s0, time_preserve0 ;restore the register contents
FETCH s1, time_preserve1
FETCH s2, time_preserve2
FETCH s3, time_preserve3
FETCH s4, time_preserve4
FETCH s5, time_preserve5
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.
;
1char_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 as 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.
;
2char_to_value: FETCH s0, (s1) ;read 'tens' character
CALL 1char_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 1char_to_value ;convert to numerical value
RETURN C ;bad character - CARRY set
ADD s2, s0 ;add units to result and clear CARRY flag
RETURN
;
;
;Interrupt service routine (ISR)
;
;The interrupt is used to increment a 16-bit counter formed with two registers
;called [int_counter_msb,int_counter_lsb]. This provides a count of the number
;of micro-seconds elapsed. The counter is 'free running' in that it will count
;up to 65,535 and then roll over to zero. The count value is then used in other
;parts of the program as required and where it is less time critical.
;
;The ISR only uses the specified counter registers
;
ADDRESS 3FC
ISR: ADD int_counter_lsb, 01 ;add 1us to 16-bit counter
ADDCY int_counter_msb, 00
RETURNI ENABLE
;
;Interrupt vector
;
ADDRESS 3FF
JUMP ISR
;
;
;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_semi_colon, 3B
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_BS, 08 ;Back Space command character
;
Go to most recent revision | Compare with Previous | Blame | View Log