1 |
2 |
ameziti |
;KCPSM3 Program - Real Time Clock with UART communication.
|
2 |
|
|
;
|
3 |
|
|
;Ken Chapman - Xilinx Ltd - October 2003
|
4 |
|
|
;
|
5 |
|
|
;
|
6 |
|
|
;Port definitions
|
7 |
|
|
;
|
8 |
|
|
CONSTANT UART_status_port, 00 ;UART status input
|
9 |
|
|
CONSTANT tx_half_full, 01 ; Transmitter half full - bit0
|
10 |
|
|
CONSTANT tx_full, 02 ; FIFO full - bit1
|
11 |
|
|
CONSTANT rx_half_full, 04 ; Receiver half full - bit2
|
12 |
|
|
CONSTANT rx_full, 08 ; FIFO full - bit3
|
13 |
|
|
CONSTANT rx_data_present, 10 ; data present - bit4
|
14 |
|
|
;
|
15 |
|
|
CONSTANT UART_read_port, 01 ;UART Rx data input
|
16 |
|
|
;
|
17 |
|
|
CONSTANT UART_write_port, 01 ;UART Tx data output
|
18 |
|
|
;
|
19 |
|
|
CONSTANT alarm_port, 00 ;Alarm output
|
20 |
|
|
CONSTANT alarm_control, 01 ; bit0
|
21 |
|
|
;
|
22 |
|
|
;Special Register usage
|
23 |
|
|
;
|
24 |
|
|
NAMEREG sF, UART_data ;used to pass data to and from the UART
|
25 |
|
|
;
|
26 |
|
|
NAMEREG sE, store_pointer ;used to pass location of data in scratch pad memory
|
27 |
|
|
;
|
28 |
|
|
;Two registers to form a 16-bit counter used to count
|
29 |
|
|
;interrupt pulses generated at 1us intervals.
|
30 |
|
|
;
|
31 |
|
|
NAMEREG sD, int_counter_lsb ;lower 8-bits
|
32 |
|
|
NAMEREG sC, int_counter_msb ;upper 8-bits
|
33 |
|
|
;
|
34 |
|
|
;
|
35 |
|
|
;Scratch Pad Memory Locations
|
36 |
|
|
;
|
37 |
|
|
;
|
38 |
|
|
CONSTANT us_time_stamp_lsb, 00 ;16-bit micro-second time stamp
|
39 |
|
|
CONSTANT us_time_stamp_msb, 01
|
40 |
|
|
;
|
41 |
|
|
CONSTANT us_time_lsb, 02 ;16-bit micro-second real time value
|
42 |
|
|
CONSTANT us_time_msb, 03
|
43 |
|
|
;
|
44 |
|
|
CONSTANT ms_time_lsb, 04 ;16-bit milli-second real time value
|
45 |
|
|
CONSTANT ms_time_msb, 05
|
46 |
|
|
;
|
47 |
|
|
CONSTANT real_time_hours, 06 ;Current clock time
|
48 |
|
|
CONSTANT real_time_minutes, 07
|
49 |
|
|
CONSTANT real_time_seconds, 08
|
50 |
|
|
;
|
51 |
|
|
CONSTANT alarm_time_hours, 09 ;Alarm time
|
52 |
|
|
CONSTANT alarm_time_minutes, 0A
|
53 |
|
|
CONSTANT alarm_time_seconds, 0B
|
54 |
|
|
;
|
55 |
|
|
CONSTANT alarm_status, 0C ;Alarm status
|
56 |
|
|
CONSTANT alarm_active, 01 ; bit0 - Alarm is active
|
57 |
|
|
CONSTANT alarm_armed, 02 ; bit1 - Alarm is armed
|
58 |
|
|
;
|
59 |
|
|
CONSTANT time_preserve0, 10 ;storage for protection of registers
|
60 |
|
|
CONSTANT time_preserve1, 11 ;used by the real time clock routine.
|
61 |
|
|
CONSTANT time_preserve2, 12
|
62 |
|
|
CONSTANT time_preserve3, 13
|
63 |
|
|
CONSTANT time_preserve4, 14
|
64 |
|
|
CONSTANT time_preserve5, 15
|
65 |
|
|
;
|
66 |
|
|
;UART character strings will be stored in scratch pad memory ending in carriage return.
|
67 |
|
|
;A string can be up to 16 characters with the start location defined by this constant.
|
68 |
|
|
;
|
69 |
|
|
CONSTANT string_start, 20
|
70 |
|
|
;
|
71 |
|
|
;
|
72 |
|
|
;Initialise the system
|
73 |
|
|
;
|
74 |
|
|
;
|
75 |
|
|
cold_start: LOAD s0, 00 ;clear all time values
|
76 |
|
|
STORE s0, us_time_stamp_lsb
|
77 |
|
|
STORE s0, us_time_stamp_msb
|
78 |
|
|
STORE s0, us_time_lsb
|
79 |
|
|
STORE s0, us_time_msb
|
80 |
|
|
STORE s0, ms_time_lsb
|
81 |
|
|
STORE s0, ms_time_msb
|
82 |
|
|
STORE s0, real_time_hours
|
83 |
|
|
STORE s0, real_time_minutes
|
84 |
|
|
STORE s0, real_time_seconds
|
85 |
|
|
STORE s0, alarm_time_hours
|
86 |
|
|
STORE s0, alarm_time_minutes
|
87 |
|
|
STORE s0, alarm_time_seconds
|
88 |
|
|
STORE s0, alarm_status ;clear and disable alarm
|
89 |
|
|
CALL alarm_drive ;turn off alarm control output port
|
90 |
|
|
LOAD int_counter_lsb, 00 ;clear 'us' interrupt counter
|
91 |
|
|
LOAD int_counter_msb, 00
|
92 |
|
|
ENABLE INTERRUPT ;enable the 1us interrupts
|
93 |
|
|
;
|
94 |
|
|
;
|
95 |
|
|
;Start of the main program loop.
|
96 |
|
|
;
|
97 |
|
|
;A prompt is transmitted to the UART transmitter and then
|
98 |
|
|
;a command can be entered and interpreted.
|
99 |
|
|
;
|
100 |
|
|
;
|
101 |
|
|
prompt_input: CALL send_prompt ;Prompt 'KCPSM3>'
|
102 |
|
|
CALL receive_string ;obtain input string and maintain the time
|
103 |
|
|
;
|
104 |
|
|
;
|
105 |
|
|
;Parse the string and perform actions as required
|
106 |
|
|
;
|
107 |
|
|
;
|
108 |
|
|
;
|
109 |
|
|
LOAD s1, string_start
|
110 |
|
|
CALL fetch_char_from_memory
|
111 |
|
|
COMPARE s0, character_CR ;carriage return does nothing
|
112 |
|
|
JUMP Z, prompt_input
|
113 |
|
|
COMPARE s0, character_T ;start of 'TIME' command?
|
114 |
|
|
JUMP Z, test_for_TIME
|
115 |
|
|
COMPARE s0, character_A ;start of 'ALARM' command?
|
116 |
|
|
JUMP Z, test_for_ALARM
|
117 |
|
|
;
|
118 |
|
|
;trap other command starts here
|
119 |
|
|
;
|
120 |
|
|
bad_input_command: CALL send_Syntax_Error ;no valid command
|
121 |
|
|
JUMP Z, prompt_input
|
122 |
|
|
;
|
123 |
|
|
;
|
124 |
|
|
test_for_TIME: CALL fetch_char_from_memory
|
125 |
|
|
COMPARE s0, character_I ;test for rest of 'TIME'
|
126 |
|
|
JUMP NZ, bad_input_command
|
127 |
|
|
CALL fetch_char_from_memory
|
128 |
|
|
COMPARE s0, character_M
|
129 |
|
|
JUMP NZ, bad_input_command
|
130 |
|
|
CALL fetch_char_from_memory
|
131 |
|
|
COMPARE s0, character_E
|
132 |
|
|
JUMP NZ, bad_input_command
|
133 |
|
|
;now have a valid TIME command to process
|
134 |
|
|
CALL fetch_char_from_memory
|
135 |
|
|
COMPARE s0, character_CR ;carriage return means display time
|
136 |
|
|
JUMP NZ, set_time_command
|
137 |
|
|
CALL transmit_time ;transmit time to UART
|
138 |
|
|
JUMP prompt_input
|
139 |
|
|
set_time_command: COMPARE s0, character_space
|
140 |
|
|
JUMP NZ, bad_input_command
|
141 |
|
|
CALL test_time_string ;interpret 'hh:mm:ss' string
|
142 |
|
|
JUMP C, prompt_input ;test for invalid input
|
143 |
|
|
STORE s6, real_time_hours ;set new time into clock
|
144 |
|
|
STORE s5, real_time_minutes
|
145 |
|
|
STORE s4, real_time_seconds
|
146 |
|
|
STORE s0, ms_time_lsb ;clear 'ms' counter (s0=00)
|
147 |
|
|
STORE s0, ms_time_msb
|
148 |
|
|
CALL transmit_time ;transmit new time to UART
|
149 |
|
|
JUMP prompt_input
|
150 |
|
|
;
|
151 |
|
|
;
|
152 |
|
|
test_for_ALARM: CALL fetch_char_from_memory
|
153 |
|
|
COMPARE s0, character_L ;test for rest of 'ALARM'
|
154 |
|
|
JUMP NZ, bad_input_command
|
155 |
|
|
CALL fetch_char_from_memory
|
156 |
|
|
COMPARE s0, character_A
|
157 |
|
|
JUMP NZ, bad_input_command
|
158 |
|
|
CALL fetch_char_from_memory
|
159 |
|
|
COMPARE s0, character_R
|
160 |
|
|
JUMP NZ, bad_input_command
|
161 |
|
|
CALL fetch_char_from_memory
|
162 |
|
|
COMPARE s0, character_M
|
163 |
|
|
JUMP NZ, bad_input_command
|
164 |
|
|
;now have a valid ALARM command to process
|
165 |
|
|
CALL fetch_char_from_memory
|
166 |
|
|
COMPARE s0, character_CR ;carriage return means display alarm time
|
167 |
|
|
JUMP NZ, set_alarm_command
|
168 |
|
|
CALL transmit_alarm_time ;transmit time to UART
|
169 |
|
|
JUMP prompt_input
|
170 |
|
|
set_alarm_command: COMPARE s0, character_space ;test for ON or OFF command
|
171 |
|
|
JUMP NZ, bad_input_command
|
172 |
|
|
CALL fetch_char_from_memory
|
173 |
|
|
COMPARE s0, character_O
|
174 |
|
|
JUMP Z, set_alarm_on_off
|
175 |
|
|
SUB s1, 01 ;move memory pointer back to first character of 'hh:mm:ss' string
|
176 |
|
|
CALL test_time_string ;interpret 'hh:mm:ss' string
|
177 |
|
|
JUMP C, prompt_input ;test for invalid input
|
178 |
|
|
STORE s6, alarm_time_hours ;set new time into clock
|
179 |
|
|
STORE s5, alarm_time_minutes
|
180 |
|
|
STORE s4, alarm_time_seconds
|
181 |
|
|
CALL transmit_alarm_time ;transmit new alarm time and status
|
182 |
|
|
JUMP prompt_input
|
183 |
|
|
set_alarm_on_off: CALL fetch_char_from_memory
|
184 |
|
|
COMPARE s0, character_N ;test for 'ON'
|
185 |
|
|
JUMP NZ, test_OFF
|
186 |
|
|
CALL fetch_char_from_memory
|
187 |
|
|
COMPARE s0, character_CR
|
188 |
|
|
JUMP NZ, bad_input_command
|
189 |
|
|
FETCH s0, alarm_status ;turn alarm on
|
190 |
|
|
OR s0, alarm_armed
|
191 |
|
|
STORE s0, alarm_status
|
192 |
|
|
CALL transmit_alarm_time ;transmit alarm time and status
|
193 |
|
|
JUMP prompt_input
|
194 |
|
|
test_OFF: COMPARE s0, character_F ;test for for 'OFF'
|
195 |
|
|
JUMP NZ, bad_input_command
|
196 |
|
|
CALL fetch_char_from_memory
|
197 |
|
|
COMPARE s0, character_F
|
198 |
|
|
JUMP NZ, bad_input_command
|
199 |
|
|
CALL fetch_char_from_memory
|
200 |
|
|
COMPARE s0, character_CR
|
201 |
|
|
JUMP NZ, bad_input_command
|
202 |
|
|
LOAD s0, 00 ;turn alarm off and stop an active alarm
|
203 |
|
|
STORE s0, alarm_status
|
204 |
|
|
CALL alarm_drive ;turn off alarm
|
205 |
|
|
CALL transmit_alarm_time ;transmit alarm time and status
|
206 |
|
|
JUMP prompt_input
|
207 |
|
|
;
|
208 |
|
|
;
|
209 |
|
|
;
|
210 |
|
|
;
|
211 |
|
|
;Read an 'hh:mm:ss' time string and provide new values.
|
212 |
|
|
;
|
213 |
|
|
;The string must be provided in successive scratch pad memory locations
|
214 |
|
|
;with the s1 register containing the location of the first character.
|
215 |
|
|
;
|
216 |
|
|
;A correct time specification will result in the return of new values
|
217 |
|
|
;as follows:-
|
218 |
|
|
;
|
219 |
|
|
; s6 = hours
|
220 |
|
|
; s5 = minutes
|
221 |
|
|
; s4 = seconds
|
222 |
|
|
;
|
223 |
|
|
;If the syntax is incorrect or values are not in the correct ranges an
|
224 |
|
|
;'Invalid Time' message will be transmitted and the CARRY flag will be set
|
225 |
|
|
;
|
226 |
|
|
;Registers used s0, s1, s6, s5 and s4
|
227 |
|
|
;
|
228 |
|
|
test_time_string: CALL 2char_to_value ;obtain hours value
|
229 |
|
|
JUMP C, invalid_time ;test for non-decimal characters
|
230 |
|
|
LOAD s6, s2 ;remember hours
|
231 |
|
|
ADD s1, 01 ;increment memory pointer past hours
|
232 |
|
|
CALL fetch_char_from_memory
|
233 |
|
|
COMPARE s0, character_colon ;test for colon
|
234 |
|
|
JUMP NZ, invalid_time
|
235 |
|
|
CALL 2char_to_value ;obtain minutes value
|
236 |
|
|
JUMP C, invalid_time ;test for non-decimal characters
|
237 |
|
|
LOAD s5, s2 ;remember minutes
|
238 |
|
|
ADD s1, 01 ;increment memory pointer past minutes
|
239 |
|
|
CALL fetch_char_from_memory
|
240 |
|
|
COMPARE s0, character_colon ;test for colon
|
241 |
|
|
JUMP NZ, invalid_time
|
242 |
|
|
CALL 2char_to_value ;obtain seconds value
|
243 |
|
|
JUMP C, invalid_time ;test for non-decimal characters
|
244 |
|
|
LOAD s4, s2 ;remember minutes
|
245 |
|
|
ADD s1, 01 ;increment memory pointer past seconds
|
246 |
|
|
CALL fetch_char_from_memory
|
247 |
|
|
COMPARE s0, character_CR ;finish with carriage return
|
248 |
|
|
JUMP NZ, invalid_time
|
249 |
|
|
;Have values for hh:mm:ss but need to test if each is valid range.
|
250 |
|
|
COMPARE s6, hours_in_a_day
|
251 |
|
|
JUMP NC, invalid_time
|
252 |
|
|
COMPARE s5, minutes_in_an_hour
|
253 |
|
|
JUMP NC, invalid_time
|
254 |
|
|
COMPARE s4, seconds_in_a_minute
|
255 |
|
|
JUMP NC, invalid_time
|
256 |
|
|
LOAD s0, 00
|
257 |
|
|
SR0 s0 ;reset CARRY flag (with s0=0)
|
258 |
|
|
RETURN ;time string was OK
|
259 |
|
|
invalid_time: CALL send_Invalid
|
260 |
|
|
CALL send_space
|
261 |
|
|
CALL send_Time
|
262 |
|
|
LOAD s0, 01
|
263 |
|
|
SR0 s0 ;set CARRY flag
|
264 |
|
|
RETURN ;time string was bad
|
265 |
|
|
;
|
266 |
|
|
;
|
267 |
|
|
;Fetch character from memory, convert to upper case
|
268 |
|
|
;and increment memory pointer.
|
269 |
|
|
;
|
270 |
|
|
;The memory pointer is provided in register s1.
|
271 |
|
|
;The character obtained is returned in register s0.
|
272 |
|
|
;
|
273 |
|
|
;Registers used s0 and s1.
|
274 |
|
|
;
|
275 |
|
|
fetch_char_from_memory: FETCH s0, (s1) ;read character
|
276 |
|
|
CALL upper_case ;convert to upper case
|
277 |
|
|
ADD s1, 01 ;increment memory pointer
|
278 |
|
|
RETURN
|
279 |
|
|
;
|
280 |
|
|
;
|
281 |
|
|
;
|
282 |
|
|
;Read one character from the UART
|
283 |
|
|
;
|
284 |
|
|
;Character read will be returned in a register called 'UART_data' and will be
|
285 |
|
|
;echoed to the UART transmitter.
|
286 |
|
|
;
|
287 |
|
|
;The routine first tests the receiver FIFO buffer to see if data is present.
|
288 |
|
|
;If the FIFO is empty, the routine waits until there is a character to read.
|
289 |
|
|
;As this could take any amount of time the wait loop includes a call to the
|
290 |
|
|
;subroutine which updates the real time clock.
|
291 |
|
|
;
|
292 |
|
|
;Registers used s0 and UART_data
|
293 |
|
|
;
|
294 |
|
|
read_from_UART: INPUT s0, UART_status_port ;test Rx_FIFO buffer
|
295 |
|
|
TEST s0, rx_data_present
|
296 |
|
|
JUMP NZ, read_character
|
297 |
|
|
CALL update_time ;Perform useful operation whilst waiting
|
298 |
|
|
JUMP read_from_UART
|
299 |
|
|
read_character: INPUT UART_data, UART_read_port ;read from FIFO
|
300 |
|
|
CALL send_to_UART ;echo received character
|
301 |
|
|
RETURN
|
302 |
|
|
;
|
303 |
|
|
;
|
304 |
|
|
;
|
305 |
|
|
;Transmit one character to the UART
|
306 |
|
|
;
|
307 |
|
|
;Character supplied in register called 'UART_data'.
|
308 |
|
|
;
|
309 |
|
|
;The routine first tests the transmit FIFO buffer to see if it is full.
|
310 |
|
|
;If the FIFO is full, the routine waits until there is space which could
|
311 |
|
|
;be as long as it takes to transmit one complete character.
|
312 |
|
|
;
|
313 |
|
|
; Baud Rate Time per Character (10 bits)
|
314 |
|
|
; 9600 1,024us
|
315 |
|
|
; 19200 521us
|
316 |
|
|
; 38400 260us
|
317 |
|
|
; 57600 174us
|
318 |
|
|
; 115200 87us
|
319 |
|
|
;
|
320 |
|
|
;Since this is a relatively long duration, the wait loop includes a
|
321 |
|
|
;call to the subroutine which updates the real time clock.
|
322 |
|
|
;
|
323 |
|
|
;Registers used s0
|
324 |
|
|
;
|
325 |
|
|
send_to_UART: INPUT s0, UART_status_port ;test Tx_FIFO buffer
|
326 |
|
|
TEST s0, tx_full
|
327 |
|
|
JUMP Z, UART_write
|
328 |
|
|
CALL update_time ;Perform useful operation whilst waiting
|
329 |
|
|
JUMP send_to_UART
|
330 |
|
|
UART_write: OUTPUT UART_data, UART_write_port
|
331 |
|
|
RETURN
|
332 |
|
|
;
|
333 |
|
|
;
|
334 |
|
|
;
|
335 |
|
|
;
|
336 |
|
|
;Alarm output
|
337 |
|
|
;
|
338 |
|
|
;Uses the alarm status scratch pad memory to set or reset the alarm
|
339 |
|
|
;control bit on the alarm output port.
|
340 |
|
|
;
|
341 |
|
|
;Registers used s0
|
342 |
|
|
;
|
343 |
|
|
alarm_drive: FETCH s0, alarm_status ;read status
|
344 |
|
|
AND s0, alarm_active ;isolate bit0
|
345 |
|
|
OUTPUT s0, alarm_port
|
346 |
|
|
RETURN
|
347 |
|
|
;
|
348 |
|
|
;
|
349 |
|
|
;
|
350 |
|
|
;
|
351 |
|
|
;
|
352 |
|
|
;Transmit the time to the UART port in the format hh:mm:ss and end
|
353 |
|
|
;with a carriage return.
|
354 |
|
|
;
|
355 |
|
|
;The time to converted must be stored in 3 scratch pad memory locations as
|
356 |
|
|
;defined below. A register named 'store_pointer' must provide the address of
|
357 |
|
|
;first location.
|
358 |
|
|
;
|
359 |
|
|
; Address Data
|
360 |
|
|
;
|
361 |
|
|
; store_pointer ----> hours
|
362 |
|
|
; store_pointer + 1 ----> minutes
|
363 |
|
|
; store_pointer + 1 ----> seconds
|
364 |
|
|
;
|
365 |
|
|
;The routine first converts the time into an ASCII string stored in scratch
|
366 |
|
|
;pad memory starting at a location specified by a constant named 'string_start'.
|
367 |
|
|
;The string will then be transmitted.
|
368 |
|
|
;
|
369 |
|
|
;Registers used s0, s1, s2, 'store_pointer' and 'UART_data'.
|
370 |
|
|
;
|
371 |
|
|
transmit_time: LOAD store_pointer, real_time_hours ;locate current time in memory
|
372 |
|
|
CALL time_to_ASCII
|
373 |
|
|
CALL transmit_string
|
374 |
|
|
RETURN
|
375 |
|
|
;
|
376 |
|
|
;
|
377 |
|
|
;Transmit the alarm time and status to the UART port in the format hh:mm:ss and
|
378 |
|
|
;ending with carriage return.
|
379 |
|
|
;
|
380 |
|
|
;The alarm time to converted must be stored in 3 scratch pad memory locations as
|
381 |
|
|
;defined below. A register named 'store_pointer' must provide the address of
|
382 |
|
|
;first location.
|
383 |
|
|
;
|
384 |
|
|
; Address Data
|
385 |
|
|
;
|
386 |
|
|
; store_pointer ----> hours
|
387 |
|
|
; store_pointer + 1 ----> minutes
|
388 |
|
|
; store_pointer + 1 ----> seconds
|
389 |
|
|
;
|
390 |
|
|
;The routine first converts the time into an ASCII string stored in scratch
|
391 |
|
|
;pad memory starting at a location specified by a constant named 'string_start'.
|
392 |
|
|
;The string will then be transmitted.
|
393 |
|
|
;
|
394 |
|
|
;Registers used s0, s1, s2, 'store_pointer' and 'UART_data'.
|
395 |
|
|
;
|
396 |
|
|
transmit_alarm_time: LOAD store_pointer, alarm_time_hours ;locate alarm time in memory
|
397 |
|
|
CALL time_to_ASCII
|
398 |
|
|
CALL transmit_string
|
399 |
|
|
CALL send_Alarm
|
400 |
|
|
CALL send_space
|
401 |
|
|
FETCH s0, alarm_status ;read alarm status
|
402 |
|
|
TEST s0, alarm_active ;test for active
|
403 |
|
|
JUMP Z, test_armed
|
404 |
|
|
CALL send_Active
|
405 |
|
|
RETURN
|
406 |
|
|
test_armed: TEST s0, alarm_armed ;test for on
|
407 |
|
|
JUMP Z, alarm_is_off
|
408 |
|
|
CALL send_ON
|
409 |
|
|
RETURN
|
410 |
|
|
alarm_is_off: CALL send_OFF
|
411 |
|
|
RETURN
|
412 |
|
|
;
|
413 |
|
|
;
|
414 |
|
|
;Transmit ASCII string to UART
|
415 |
|
|
;
|
416 |
|
|
;An ASCII string must be provided in scratch pad memory commencing at the
|
417 |
|
|
;location specified by a constant named 'string_start'. The string must
|
418 |
|
|
;end with a carriage return (0D).
|
419 |
|
|
;
|
420 |
|
|
;Registers used s1 and 'UART_data'.
|
421 |
|
|
; s0 is then used in subroutine 'send_to_UART'
|
422 |
|
|
;
|
423 |
|
|
transmit_string: LOAD s1, string_start ;locate start of string
|
424 |
|
|
next_char_tx: FETCH UART_data, (s1) ;read character from memory
|
425 |
|
|
CALL send_to_UART ;transmit character
|
426 |
|
|
COMPARE UART_data, character_CR ;test for last character
|
427 |
|
|
RETURN Z
|
428 |
|
|
ADD s1, 01 ;move to next character
|
429 |
|
|
JUMP next_char_tx
|
430 |
|
|
;
|
431 |
|
|
;
|
432 |
|
|
;Receive ASCII string from UART
|
433 |
|
|
;
|
434 |
|
|
;An ASCII string will be read from the UART and stored in scratch pad memory
|
435 |
|
|
;commencing at the location specified by a constant named 'string_start'.
|
436 |
|
|
;The string will will have a maximum length of 16 characters including a
|
437 |
|
|
;carriage return (0D) denoting the end of the string.
|
438 |
|
|
;
|
439 |
|
|
;As each character is read, it is echoed to the UART transmitter.
|
440 |
|
|
;Some minor editing is supported using backspace (BS=08) which is used
|
441 |
|
|
;to adjust what is stored in scratch pad memory and adjust the display
|
442 |
|
|
;on the terminal screen using characters sent to the UART transmitter.
|
443 |
|
|
;
|
444 |
|
|
;A test is made for the receiver FIFO becoming full. A full status is treated as
|
445 |
|
|
;a potential error situation and will result in a 'Overflow Error' message being
|
446 |
|
|
;transmitted to the UART, the receiver FIFO being purged of all data and an
|
447 |
|
|
;empty string being stored (carriage return at first location).
|
448 |
|
|
;
|
449 |
|
|
;Registers used s0, s1, s2 and 'UART_data'.
|
450 |
|
|
;
|
451 |
|
|
receive_string: LOAD s1, string_start ;locate start of string
|
452 |
|
|
LOAD s2, s1 ;compute 16 character address
|
453 |
|
|
ADD s2, 10
|
454 |
|
|
receive_full_test: INPUT s0, UART_status_port ;test Rx_FIFO buffer for full
|
455 |
|
|
TEST s0, rx_full
|
456 |
|
|
JUMP NZ, read_error
|
457 |
|
|
CALL read_from_UART ;obtain and echo character
|
458 |
|
|
STORE UART_data, (s1) ;write to memory
|
459 |
|
|
COMPARE UART_data, character_CR ;test for end of string
|
460 |
|
|
RETURN Z
|
461 |
|
|
COMPARE UART_data, character_BS ;test for back space
|
462 |
|
|
JUMP Z, BS_edit
|
463 |
|
|
ADD s1, 01 ;increment memory pointer
|
464 |
|
|
COMPARE s1, s2 ;test for pointer exceeding 16 characters
|
465 |
|
|
JUMP NZ, receive_full_test ;next character
|
466 |
|
|
CALL send_backspace ;hold end of string position on terminal display
|
467 |
|
|
BS_edit: SUB s1, 01 ;memory pointer back one
|
468 |
|
|
COMPARE s1, string_start ;test for under flow
|
469 |
|
|
JUMP C, string_start_again
|
470 |
|
|
CALL send_space ;clear character at current position
|
471 |
|
|
CALL send_backspace ;position cursor
|
472 |
|
|
JUMP receive_full_test ;next character
|
473 |
|
|
string_start_again: CALL send_greater_than ;restore '>' at prompt
|
474 |
|
|
JUMP receive_string ;begin again
|
475 |
|
|
;Receiver buffer overflow condition
|
476 |
|
|
read_error: CALL send_CR ;Transmit error message
|
477 |
|
|
STORE UART_data, string_start ;empty string in memory (start with CR)
|
478 |
|
|
CALL send_Overflow_Error
|
479 |
|
|
CALL send_CR
|
480 |
|
|
clear_UART_Rx_loop: INPUT s0, UART_status_port ;test Rx_FIFO buffer for data
|
481 |
|
|
TEST s0, rx_data_present
|
482 |
|
|
RETURN Z ;finish when buffer is empty
|
483 |
|
|
INPUT UART_data, UART_read_port ;read from FIFO and ignore
|
484 |
|
|
JUMP clear_UART_Rx_loop
|
485 |
|
|
;
|
486 |
|
|
;
|
487 |
|
|
;
|
488 |
|
|
;Send Carriage Return to the UART
|
489 |
|
|
;
|
490 |
|
|
send_CR: LOAD UART_data, character_CR
|
491 |
|
|
CALL send_to_UART
|
492 |
|
|
RETURN
|
493 |
|
|
;
|
494 |
|
|
;
|
495 |
|
|
;
|
496 |
|
|
;Send a space to the UART
|
497 |
|
|
;
|
498 |
|
|
send_space: LOAD UART_data, character_space
|
499 |
|
|
CALL send_to_UART
|
500 |
|
|
RETURN
|
501 |
|
|
;
|
502 |
|
|
;
|
503 |
|
|
;Send a back space to the UART
|
504 |
|
|
;
|
505 |
|
|
send_backspace: LOAD UART_data, character_BS
|
506 |
|
|
CALL send_to_UART
|
507 |
|
|
RETURN
|
508 |
|
|
;
|
509 |
|
|
;Send 'Syntax Error' to the UART
|
510 |
|
|
;
|
511 |
|
|
send_Syntax_Error: LOAD UART_data, character_S
|
512 |
|
|
CALL send_to_UART
|
513 |
|
|
LOAD UART_data, character_y
|
514 |
|
|
CALL send_to_UART
|
515 |
|
|
LOAD UART_data, character_n
|
516 |
|
|
CALL send_to_UART
|
517 |
|
|
LOAD UART_data, character_t
|
518 |
|
|
CALL send_to_UART
|
519 |
|
|
LOAD UART_data, character_a
|
520 |
|
|
CALL send_to_UART
|
521 |
|
|
LOAD UART_data, character_x
|
522 |
|
|
CALL send_to_UART
|
523 |
|
|
JUMP send_space_Error
|
524 |
|
|
;
|
525 |
|
|
;Send 'Overflow Error' to the UART
|
526 |
|
|
;
|
527 |
|
|
send_Overflow_Error: LOAD UART_data, character_O
|
528 |
|
|
CALL send_to_UART
|
529 |
|
|
LOAD UART_data, character_v
|
530 |
|
|
CALL send_to_UART
|
531 |
|
|
LOAD UART_data, character_e
|
532 |
|
|
CALL send_to_UART
|
533 |
|
|
LOAD UART_data, character_r
|
534 |
|
|
CALL send_to_UART
|
535 |
|
|
LOAD UART_data, character_f
|
536 |
|
|
CALL send_to_UART
|
537 |
|
|
LOAD UART_data, character_l
|
538 |
|
|
CALL send_to_UART
|
539 |
|
|
LOAD UART_data, character_o
|
540 |
|
|
CALL send_to_UART
|
541 |
|
|
LOAD UART_data, character_w
|
542 |
|
|
CALL send_to_UART
|
543 |
|
|
send_space_Error: CALL send_space
|
544 |
|
|
;
|
545 |
|
|
;Send 'Error' to the UART
|
546 |
|
|
;
|
547 |
|
|
send_Error: LOAD UART_data, character_E
|
548 |
|
|
CALL send_to_UART
|
549 |
|
|
LOAD UART_data, character_r
|
550 |
|
|
CALL send_to_UART
|
551 |
|
|
CALL send_to_UART
|
552 |
|
|
LOAD UART_data, character_o
|
553 |
|
|
CALL send_to_UART
|
554 |
|
|
LOAD UART_data, character_r
|
555 |
|
|
CALL send_to_UART
|
556 |
|
|
RETURN
|
557 |
|
|
;
|
558 |
|
|
;Send 'KCPSM3>' prompt to the UART
|
559 |
|
|
;
|
560 |
|
|
send_prompt: CALL send_CR ;start new line
|
561 |
|
|
LOAD UART_data, character_K
|
562 |
|
|
CALL send_to_UART
|
563 |
|
|
LOAD UART_data, character_C
|
564 |
|
|
CALL send_to_UART
|
565 |
|
|
LOAD UART_data, character_P
|
566 |
|
|
CALL send_to_UART
|
567 |
|
|
LOAD UART_data, character_S
|
568 |
|
|
CALL send_to_UART
|
569 |
|
|
LOAD UART_data, character_M
|
570 |
|
|
CALL send_to_UART
|
571 |
|
|
LOAD UART_data, character_3
|
572 |
|
|
CALL send_to_UART
|
573 |
|
|
;
|
574 |
|
|
;Send '>' character to the UART
|
575 |
|
|
;
|
576 |
|
|
send_greater_than: LOAD UART_data, character_greater_than
|
577 |
|
|
CALL send_to_UART
|
578 |
|
|
RETURN
|
579 |
|
|
;
|
580 |
|
|
;Send 'Invalid' string to the UART
|
581 |
|
|
;
|
582 |
|
|
send_Invalid: LOAD UART_data, character_I
|
583 |
|
|
CALL send_to_UART
|
584 |
|
|
LOAD UART_data, character_n
|
585 |
|
|
CALL send_to_UART
|
586 |
|
|
LOAD UART_data, character_v
|
587 |
|
|
CALL send_to_UART
|
588 |
|
|
LOAD UART_data, character_a
|
589 |
|
|
CALL send_to_UART
|
590 |
|
|
LOAD UART_data, character_l
|
591 |
|
|
CALL send_to_UART
|
592 |
|
|
LOAD UART_data, character_i
|
593 |
|
|
CALL send_to_UART
|
594 |
|
|
LOAD UART_data, character_d
|
595 |
|
|
CALL send_to_UART
|
596 |
|
|
RETURN
|
597 |
|
|
;
|
598 |
|
|
;Send 'Time' string to the UART
|
599 |
|
|
;
|
600 |
|
|
send_Time: LOAD UART_data, character_T
|
601 |
|
|
CALL send_to_UART
|
602 |
|
|
LOAD UART_data, character_i
|
603 |
|
|
CALL send_to_UART
|
604 |
|
|
LOAD UART_data, character_m
|
605 |
|
|
CALL send_to_UART
|
606 |
|
|
LOAD UART_data, character_e
|
607 |
|
|
CALL send_to_UART
|
608 |
|
|
RETURN
|
609 |
|
|
;
|
610 |
|
|
;Send 'Alarm' string to the UART
|
611 |
|
|
;
|
612 |
|
|
send_Alarm: LOAD UART_data, character_A
|
613 |
|
|
CALL send_to_UART
|
614 |
|
|
LOAD UART_data, character_l
|
615 |
|
|
CALL send_to_UART
|
616 |
|
|
LOAD UART_data, character_a
|
617 |
|
|
CALL send_to_UART
|
618 |
|
|
LOAD UART_data, character_r
|
619 |
|
|
CALL send_to_UART
|
620 |
|
|
LOAD UART_data, character_m
|
621 |
|
|
CALL send_to_UART
|
622 |
|
|
RETURN
|
623 |
|
|
;
|
624 |
|
|
;Send 'OFF' string to the UART
|
625 |
|
|
;
|
626 |
|
|
send_OFF: LOAD UART_data, character_O
|
627 |
|
|
CALL send_to_UART
|
628 |
|
|
LOAD UART_data, character_F
|
629 |
|
|
CALL send_to_UART
|
630 |
|
|
CALL send_to_UART
|
631 |
|
|
RETURN
|
632 |
|
|
;
|
633 |
|
|
;Send 'ON' string to the UART
|
634 |
|
|
;
|
635 |
|
|
send_ON: LOAD UART_data, character_O
|
636 |
|
|
CALL send_to_UART
|
637 |
|
|
LOAD UART_data, character_N
|
638 |
|
|
CALL send_to_UART
|
639 |
|
|
RETURN
|
640 |
|
|
;
|
641 |
|
|
;Send 'Active' string to the UART
|
642 |
|
|
;
|
643 |
|
|
send_Active: LOAD UART_data, character_A
|
644 |
|
|
CALL send_to_UART
|
645 |
|
|
LOAD UART_data, character_c
|
646 |
|
|
CALL send_to_UART
|
647 |
|
|
LOAD UART_data, character_t
|
648 |
|
|
CALL send_to_UART
|
649 |
|
|
LOAD UART_data, character_i
|
650 |
|
|
CALL send_to_UART
|
651 |
|
|
LOAD UART_data, character_v
|
652 |
|
|
CALL send_to_UART
|
653 |
|
|
LOAD UART_data, character_e
|
654 |
|
|
CALL send_to_UART
|
655 |
|
|
RETURN
|
656 |
|
|
;
|
657 |
|
|
;
|
658 |
|
|
;Convert time to ASCII string in scratch pad memory.
|
659 |
|
|
;
|
660 |
|
|
;The time to converted must be stored in 3 scratch pad memory locations as
|
661 |
|
|
;defined below. A register named 'store_pointer' must provide the address of
|
662 |
|
|
;first location.
|
663 |
|
|
;
|
664 |
|
|
; Address Data
|
665 |
|
|
;
|
666 |
|
|
; store_pointer ----> hours
|
667 |
|
|
; store_pointer + 1 ----> minutes
|
668 |
|
|
; store_pointer + 1 ----> seconds
|
669 |
|
|
;
|
670 |
|
|
;The resulting ASCII string will be stored in scratch pad memory starting at
|
671 |
|
|
;a location specified by a constant named 'string_start'. The string will
|
672 |
|
|
;take the format hh:mm:ss and end with a carriage return.
|
673 |
|
|
;
|
674 |
|
|
;Registers used s0, s1, s2 and 'store_pointer'.
|
675 |
|
|
;
|
676 |
|
|
time_to_ASCII: LOAD s2, string_start ;location for string
|
677 |
|
|
FETCH s0, (store_pointer) ;read hours value
|
678 |
|
|
CALL decimal_to_ASCII ;convert to ASCII
|
679 |
|
|
STORE s1, (s2) ;write hours to string
|
680 |
|
|
ADD s2, 01
|
681 |
|
|
STORE s0, (s2)
|
682 |
|
|
ADD s2, 01
|
683 |
|
|
LOAD s0, character_colon ;write ':' to string
|
684 |
|
|
STORE s0, (s2)
|
685 |
|
|
ADD s2, 01
|
686 |
|
|
ADD store_pointer, 01 ;move to minutes
|
687 |
|
|
FETCH s0, (store_pointer) ;read minutes value
|
688 |
|
|
CALL decimal_to_ASCII ;convert to ASCII
|
689 |
|
|
STORE s1, (s2) ;write minutes to string
|
690 |
|
|
ADD s2, 01
|
691 |
|
|
STORE s0, (s2)
|
692 |
|
|
ADD s2, 01
|
693 |
|
|
LOAD s0, character_colon ;write ':' to string
|
694 |
|
|
STORE s0, (s2)
|
695 |
|
|
ADD s2, 01
|
696 |
|
|
ADD store_pointer, 01 ;move to seconds
|
697 |
|
|
FETCH s0, (store_pointer) ;read seconds value
|
698 |
|
|
CALL decimal_to_ASCII ;convert to ASCII
|
699 |
|
|
STORE s1, (s2) ;write seconds to string
|
700 |
|
|
ADD s2, 01
|
701 |
|
|
STORE s0, (s2)
|
702 |
|
|
ADD s2, 01
|
703 |
|
|
LOAD s0, character_CR ;finish string with carriage return
|
704 |
|
|
STORE s0, (s2)
|
705 |
|
|
RETURN
|
706 |
|
|
;
|
707 |
|
|
;Convert value provided in register s0 into ASCII characters
|
708 |
|
|
;
|
709 |
|
|
;The value provided must in the range 0 to 99 and will be converted into
|
710 |
|
|
;two ASCII characters.
|
711 |
|
|
; The number of 'tens' will be representd by an ASCII character returned in register s1.
|
712 |
|
|
; The number of 'units' will be representd by an ASCII character returned in register s0.
|
713 |
|
|
;
|
714 |
|
|
;The ASCII representations of '0' to '9' are 30 to 39 hexadecimal which is simply 30 hex added to
|
715 |
|
|
;the actual decimal value.
|
716 |
|
|
;
|
717 |
|
|
;Registers used s0 and s1.
|
718 |
|
|
;
|
719 |
|
|
decimal_to_ASCII: LOAD s1, 30 ;load 'tens' counter with ASCII for '0'
|
720 |
|
|
test_for_ten: ADD s1, 01 ;increment 'tens' value
|
721 |
|
|
SUB s0, 0A ;try to subtract 10 from the supplied value
|
722 |
|
|
JUMP NC, test_for_ten ;repeat if subtraction was possible without underflow.
|
723 |
|
|
SUB s1, 01 ;'tens' value one less ten due to underflow
|
724 |
|
|
ADD s0, 3A ;restore units value (the remainder) and convert to ASCII
|
725 |
|
|
RETURN
|
726 |
|
|
;
|
727 |
|
|
;
|
728 |
|
|
;
|
729 |
|
|
;
|
730 |
|
|
;Real Time Clock
|
731 |
|
|
;
|
732 |
|
|
;Uses the 1us interrupt counter [int_counter_msb,int_counter_lsb] to determine how many
|
733 |
|
|
;micro-seconds have elapsed since the last update. This allows for just over 65ms between
|
734 |
|
|
;updates. Complete multiples of 1000us are used to update a 16-bit milli-second counter held
|
735 |
|
|
;in scratch pad memory locations [ms_time_stamp_msb,ms_time_stamp_msb] which in turn
|
736 |
|
|
;is used to update the real time hours, minutes and seconds clock held in scratch pad
|
737 |
|
|
;memory locations 'real_time_hours', 'real_time_minutes' and 'real_time_seconds'.
|
738 |
|
|
;
|
739 |
|
|
;The routine uses default register names s0,s1,s2,s3,s4,s5. These are preserved in scratch pad
|
740 |
|
|
;memory during the routine and restored before returning.
|
741 |
|
|
;
|
742 |
|
|
;Useful constants for real time clock operations
|
743 |
|
|
;
|
744 |
|
|
CONSTANT count_1000_lsb, E8 ;lower 8-bits of 1000 count value
|
745 |
|
|
CONSTANT count_1000_msb, 03 ;upper 8-bits of 1000 count value
|
746 |
|
|
CONSTANT hours_in_a_day, 18 ;24 hours in a day
|
747 |
|
|
CONSTANT minutes_in_an_hour, 3C ;60 minutes in an hour
|
748 |
|
|
CONSTANT seconds_in_a_minute, 3C ;60 seconds in a minute
|
749 |
|
|
;
|
750 |
|
|
update_time: STORE s0, time_preserve0 ;preserve contents of registers used during routine
|
751 |
|
|
STORE s1, time_preserve1
|
752 |
|
|
STORE s2, time_preserve2
|
753 |
|
|
STORE s3, time_preserve3
|
754 |
|
|
STORE s4, time_preserve4
|
755 |
|
|
STORE s5, time_preserve5
|
756 |
|
|
;
|
757 |
|
|
FETCH s2, us_time_stamp_lsb ;read the previous 'us' time stamp into [s3,s2]
|
758 |
|
|
FETCH s3, us_time_stamp_msb
|
759 |
|
|
DISABLE INTERRUPT ;Read and store current 'us' time stamp provided by the interrupt
|
760 |
|
|
STORE int_counter_lsb, us_time_stamp_lsb ;counter. Interrupts are disabled to ensure that both bytes relate
|
761 |
|
|
STORE int_counter_msb, us_time_stamp_msb ;to the same count value.
|
762 |
|
|
ENABLE INTERRUPT
|
763 |
|
|
FETCH s4, us_time_stamp_lsb ;read the new 'us' time stamp in [s5,s4]
|
764 |
|
|
FETCH s5, us_time_stamp_msb ;
|
765 |
|
|
SUB s4, s2 ;calculate 'us' time difference [s5,s4] = [s5,s4] - [s3,s2]
|
766 |
|
|
SUBCY s5, s3 ; (This works correctly even if counter has rolled over)
|
767 |
|
|
FETCH s2, us_time_lsb ;read current 'us' time into [s3,s2]
|
768 |
|
|
FETCH s3, us_time_msb
|
769 |
|
|
ADD s2, s4 ;add on the elapsed 'us' value [s3,s2] = [s3,s2] + [s5,s4]
|
770 |
|
|
ADDCY s3, s5
|
771 |
|
|
;determine how many 1000us (1ms) units there are (if any) in current 'us' time
|
772 |
|
|
LOAD s0, 00 ;reset 'ms' counter
|
773 |
|
|
test_1000us: SUB s2, count_1000_lsb ;subtract 1000 from [s3,s2]
|
774 |
|
|
SUBCY s3, count_1000_msb
|
775 |
|
|
JUMP C, store_us_time ;Carry indicates [s3,s2] was less than 1000us
|
776 |
|
|
ADD s0, 01 ;increment 'ms' elapsed because [s3,s2] was more or equal to 1000us
|
777 |
|
|
JUMP test_1000us ;repeat to see if more than 1ms has elapsed
|
778 |
|
|
store_us_time: ADD s2, count_1000_lsb ;add 1000 to restore 'us' value
|
779 |
|
|
ADDCY s3, count_1000_msb
|
780 |
|
|
STORE s2, us_time_lsb ;store the current value of 'us'
|
781 |
|
|
STORE s3, us_time_msb
|
782 |
|
|
;s0 holds the number of 'ms' elapsed since last update (if any).
|
783 |
|
|
FETCH s2, ms_time_lsb ;read current 'ms' time into [s3,s2]
|
784 |
|
|
FETCH s3, ms_time_msb
|
785 |
|
|
ADD s2, s0 ;add on the elapsed 'ms' value [s3,s2] = [s3,s2] + s0
|
786 |
|
|
ADDCY s3, 00
|
787 |
|
|
;determine if there are now more than 1000ms to form 1 second.
|
788 |
|
|
LOAD s0, 00 ;reset 'second' counter
|
789 |
|
|
SUB s2, count_1000_lsb ;subtract 1000 from [s3,s2]
|
790 |
|
|
SUBCY s3, count_1000_msb
|
791 |
|
|
JUMP C, restore_ms_time ;Carry indicates [s3,s2] was less than 1000ms
|
792 |
|
|
ADD s0, 01 ;increment 'second' elapsed because [s3,s2] was more or equal to 1000ms
|
793 |
|
|
JUMP store_ms_time ;new value of 'ms' is remainder of subtraction
|
794 |
|
|
restore_ms_time: ADD s2, count_1000_lsb ;add 1000 to restore 'ms' value
|
795 |
|
|
ADDCY s3, count_1000_msb
|
796 |
|
|
store_ms_time: STORE s2, ms_time_lsb ;store the current value of 'ms'
|
797 |
|
|
STORE s3, ms_time_msb
|
798 |
|
|
;s0 currently determines if one second needs to be added to the hh:mm:ss clock time
|
799 |
|
|
FETCH s1, real_time_seconds ;read seconds
|
800 |
|
|
ADD s1, s0 ;add one second if required by s0
|
801 |
|
|
COMPARE s1, seconds_in_a_minute ;test for 1 minute
|
802 |
|
|
JUMP Z, inc_minutes
|
803 |
|
|
STORE s1, real_time_seconds ;store updated seconds
|
804 |
|
|
JUMP time_update_complete
|
805 |
|
|
inc_minutes: LOAD s1, 00 ;seconds become zero
|
806 |
|
|
STORE s1, real_time_seconds
|
807 |
|
|
FETCH s1, real_time_minutes ;read minutes
|
808 |
|
|
ADD s1, 01 ;increment minutes
|
809 |
|
|
COMPARE s1, minutes_in_an_hour ;test for 1 hour
|
810 |
|
|
JUMP Z, inc_hours
|
811 |
|
|
STORE s1, real_time_minutes ;store updated minutes
|
812 |
|
|
JUMP time_update_complete
|
813 |
|
|
inc_hours: LOAD s1, 00 ;minutes become zero
|
814 |
|
|
STORE s1, real_time_minutes
|
815 |
|
|
FETCH s1, real_time_hours ;read hours
|
816 |
|
|
ADD s1, 01 ;increment hours
|
817 |
|
|
COMPARE s1, hours_in_a_day ;test for 24 hours
|
818 |
|
|
JUMP Z, reset_hours
|
819 |
|
|
STORE s1, real_time_hours ;store updated hours
|
820 |
|
|
JUMP time_update_complete
|
821 |
|
|
reset_hours: LOAD s1, 00 ;hours become zero
|
822 |
|
|
STORE s1, real_time_hours
|
823 |
|
|
;
|
824 |
|
|
;With the time updated, there is then a test for time=alarm time
|
825 |
|
|
;
|
826 |
|
|
time_update_complete: FETCH s0, real_time_hours
|
827 |
|
|
FETCH s1, alarm_time_hours ;compare hours
|
828 |
|
|
COMPARE s0, s1
|
829 |
|
|
JUMP NZ, finish_update
|
830 |
|
|
FETCH s0, real_time_minutes ;compare minutes
|
831 |
|
|
FETCH s1, alarm_time_minutes
|
832 |
|
|
COMPARE s0, s1
|
833 |
|
|
JUMP NZ, finish_update
|
834 |
|
|
FETCH s0, real_time_seconds ;compare seconds
|
835 |
|
|
FETCH s1, alarm_time_seconds
|
836 |
|
|
COMPARE s0, s1
|
837 |
|
|
JUMP NZ, finish_update
|
838 |
|
|
FETCH s0, alarm_status ;test if alarm is turned on
|
839 |
|
|
TEST s0, alarm_armed
|
840 |
|
|
JUMP Z, finish_update ;alarm was off
|
841 |
|
|
OR s0, alarm_active ;activate alarm
|
842 |
|
|
STORE s0, alarm_status
|
843 |
|
|
CALL alarm_drive
|
844 |
|
|
finish_update: FETCH s0, time_preserve0 ;restore the register contents
|
845 |
|
|
FETCH s1, time_preserve1
|
846 |
|
|
FETCH s2, time_preserve2
|
847 |
|
|
FETCH s3, time_preserve3
|
848 |
|
|
FETCH s4, time_preserve4
|
849 |
|
|
FETCH s5, time_preserve5
|
850 |
|
|
RETURN
|
851 |
|
|
;
|
852 |
|
|
;Convert character to upper case
|
853 |
|
|
;
|
854 |
|
|
;The character supplied in register s0.
|
855 |
|
|
;If the character is in the range 'a' to 'z', it is converted
|
856 |
|
|
;to the equivalent upper case character in the range 'A' to 'Z'.
|
857 |
|
|
;All other characters remain unchanged.
|
858 |
|
|
;
|
859 |
|
|
;Registers used s0.
|
860 |
|
|
;
|
861 |
|
|
upper_case: COMPARE s0, 61 ;eliminate character codes below 'a' (61 hex)
|
862 |
|
|
RETURN C
|
863 |
|
|
COMPARE s0, 7B ;eliminate character codes above 'z' (7A hex)
|
864 |
|
|
RETURN NC
|
865 |
|
|
AND s0, DF ;mask bit5 to convert to upper case
|
866 |
|
|
RETURN
|
867 |
|
|
;
|
868 |
|
|
;
|
869 |
|
|
;Convert character '0' to '9' to numerical value in range 0 to 9
|
870 |
|
|
;
|
871 |
|
|
;The character supplied in register s0. If the character is in the
|
872 |
|
|
;range '0' to '9', it is converted to the equivalent decimal value.
|
873 |
|
|
;Characters not in the range '0' to '9' are signified by the return
|
874 |
|
|
;with the CARRY flag set.
|
875 |
|
|
;
|
876 |
|
|
;Registers used s0.
|
877 |
|
|
;
|
878 |
|
|
1char_to_value: ADD s0, C6 ;reject character codes above '9' (39 hex)
|
879 |
|
|
RETURN C ;carry flag is set
|
880 |
|
|
SUB s0, F6 ;reject character codes below '0' (30 hex)
|
881 |
|
|
RETURN ;carry is set if value not in range
|
882 |
|
|
;
|
883 |
|
|
;
|
884 |
|
|
;Determine the numerical value of a two character decimal string held in
|
885 |
|
|
;scratch pad memory such the result is in the range 0 to 99 (00 to 63 hex).
|
886 |
|
|
;
|
887 |
|
|
;The string must be stored as in two consecutive memory locations and the
|
888 |
|
|
;location of the first (tens) character supplied in the s1 register.
|
889 |
|
|
;The result is provided in register s2. Strings not using characters in the
|
890 |
|
|
;range '0' to '9' are signified by the return with the CARRY flag set.
|
891 |
|
|
;
|
892 |
|
|
;Registers used s0, s1 and s2.
|
893 |
|
|
;
|
894 |
|
|
2char_to_value: FETCH s0, (s1) ;read 'tens' character
|
895 |
|
|
CALL 1char_to_value ;convert to numerical value
|
896 |
|
|
RETURN C ;bad character - CARRY set
|
897 |
|
|
LOAD s2, s0
|
898 |
|
|
SL0 s2 ;multiply 'tens' value by 10 (0A hex)
|
899 |
|
|
SL0 s2
|
900 |
|
|
ADD s2, s0
|
901 |
|
|
SL0 s2
|
902 |
|
|
ADD s1, 01 ;read 'units' character
|
903 |
|
|
FETCH s0, (s1)
|
904 |
|
|
CALL 1char_to_value ;convert to numerical value
|
905 |
|
|
RETURN C ;bad character - CARRY set
|
906 |
|
|
ADD s2, s0 ;add units to result and clear CARRY flag
|
907 |
|
|
RETURN
|
908 |
|
|
;
|
909 |
|
|
;
|
910 |
|
|
;Interrupt service routine (ISR)
|
911 |
|
|
;
|
912 |
|
|
;The interrupt is used to increment a 16-bit counter formed with two registers
|
913 |
|
|
;called [int_counter_msb,int_counter_lsb]. This provides a count of the number
|
914 |
|
|
;of micro-seconds elapsed. The counter is 'free running' in that it will count
|
915 |
|
|
;up to 65,535 and then roll over to zero. The count value is then used in other
|
916 |
|
|
;parts of the program as required and where it is less time critical.
|
917 |
|
|
;
|
918 |
|
|
;The ISR only uses the specified counter registers
|
919 |
|
|
;
|
920 |
|
|
ADDRESS 3FC
|
921 |
|
|
ISR: ADD int_counter_lsb, 01 ;add 1us to 16-bit counter
|
922 |
|
|
ADDCY int_counter_msb, 00
|
923 |
|
|
RETURNI ENABLE
|
924 |
|
|
;
|
925 |
|
|
;Interrupt vector
|
926 |
|
|
;
|
927 |
|
|
ADDRESS 3FF
|
928 |
|
|
JUMP ISR
|
929 |
|
|
;
|
930 |
|
|
;
|
931 |
|
|
;Useful constants
|
932 |
|
|
;
|
933 |
|
|
;
|
934 |
|
|
;ASCII table
|
935 |
|
|
;
|
936 |
|
|
CONSTANT character_a, 61
|
937 |
|
|
CONSTANT character_b, 62
|
938 |
|
|
CONSTANT character_c, 63
|
939 |
|
|
CONSTANT character_d, 64
|
940 |
|
|
CONSTANT character_e, 65
|
941 |
|
|
CONSTANT character_f, 66
|
942 |
|
|
CONSTANT character_g, 67
|
943 |
|
|
CONSTANT character_h, 68
|
944 |
|
|
CONSTANT character_i, 69
|
945 |
|
|
CONSTANT character_j, 6A
|
946 |
|
|
CONSTANT character_k, 6B
|
947 |
|
|
CONSTANT character_l, 6C
|
948 |
|
|
CONSTANT character_m, 6D
|
949 |
|
|
CONSTANT character_n, 6E
|
950 |
|
|
CONSTANT character_o, 6F
|
951 |
|
|
CONSTANT character_p, 70
|
952 |
|
|
CONSTANT character_q, 71
|
953 |
|
|
CONSTANT character_r, 72
|
954 |
|
|
CONSTANT character_s, 73
|
955 |
|
|
CONSTANT character_t, 74
|
956 |
|
|
CONSTANT character_u, 75
|
957 |
|
|
CONSTANT character_v, 76
|
958 |
|
|
CONSTANT character_w, 77
|
959 |
|
|
CONSTANT character_x, 78
|
960 |
|
|
CONSTANT character_y, 79
|
961 |
|
|
CONSTANT character_z, 7A
|
962 |
|
|
CONSTANT character_A, 41
|
963 |
|
|
CONSTANT character_B, 42
|
964 |
|
|
CONSTANT character_C, 43
|
965 |
|
|
CONSTANT character_D, 44
|
966 |
|
|
CONSTANT character_E, 45
|
967 |
|
|
CONSTANT character_F, 46
|
968 |
|
|
CONSTANT character_G, 47
|
969 |
|
|
CONSTANT character_H, 48
|
970 |
|
|
CONSTANT character_I, 49
|
971 |
|
|
CONSTANT character_J, 4A
|
972 |
|
|
CONSTANT character_K, 4B
|
973 |
|
|
CONSTANT character_L, 4C
|
974 |
|
|
CONSTANT character_M, 4D
|
975 |
|
|
CONSTANT character_N, 4E
|
976 |
|
|
CONSTANT character_O, 4F
|
977 |
|
|
CONSTANT character_P, 50
|
978 |
|
|
CONSTANT character_Q, 51
|
979 |
|
|
CONSTANT character_R, 52
|
980 |
|
|
CONSTANT character_S, 53
|
981 |
|
|
CONSTANT character_T, 54
|
982 |
|
|
CONSTANT character_U, 55
|
983 |
|
|
CONSTANT character_V, 56
|
984 |
|
|
CONSTANT character_W, 57
|
985 |
|
|
CONSTANT character_X, 58
|
986 |
|
|
CONSTANT character_Y, 59
|
987 |
|
|
CONSTANT character_Z, 5A
|
988 |
|
|
CONSTANT character_0, 30
|
989 |
|
|
CONSTANT character_1, 31
|
990 |
|
|
CONSTANT character_2, 32
|
991 |
|
|
CONSTANT character_3, 33
|
992 |
|
|
CONSTANT character_4, 34
|
993 |
|
|
CONSTANT character_5, 35
|
994 |
|
|
CONSTANT character_6, 36
|
995 |
|
|
CONSTANT character_7, 37
|
996 |
|
|
CONSTANT character_8, 38
|
997 |
|
|
CONSTANT character_9, 39
|
998 |
|
|
CONSTANT character_colon, 3A
|
999 |
|
|
CONSTANT character_semi_colon, 3B
|
1000 |
|
|
CONSTANT character_less_than, 3C
|
1001 |
|
|
CONSTANT character_greater_than, 3E
|
1002 |
|
|
CONSTANT character_equals, 3D
|
1003 |
|
|
CONSTANT character_space, 20
|
1004 |
|
|
CONSTANT character_CR, 0D ;carriage return
|
1005 |
|
|
CONSTANT character_question, 3F ;'?'
|
1006 |
|
|
CONSTANT character_dollar, 24
|
1007 |
|
|
CONSTANT character_BS, 08 ;Back Space command character
|
1008 |
|
|
;
|