; SERVID - Serial video display using Ubicom SX microcontroller ; $Id: servid.asm,v 1.34 2001/01/31 07:25:31 eric Exp $ ; ; Copyright 2000, 2001 Eric Smith <eric@brouhaha.com> ; ; Home page: ; http://www.brouhaha.com/ubicom/servid/ ; ; This program is free software; you can redistribute it and/or modify ; it under the terms of the GNU General Public License version 2 as published ; by the Free Software Foundation. Note that permission is not granted ; to redistribute this program under the terms of any other version of the ; General Public License. ; ; This program is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License ; along with this program; if not, write to the Free Software ; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ; ; NOTE: it is sometimes claimed that compliance with the GPL is ; awkward for commercial interests. Licenses for non-GPL use of this ; program may be negotiated with the author. ; ; This program is written to be assembled with the GPASM assembler, ; version 0.8.14 or newer: ; http://gpasm.sourceforge.net/ ; NOTE: there are references in this code to PAL and NTSC. Technically ; those are color standards. In most cases the references to PAL and NTSC ; are really intended to refer to 625/50 and 525/59.94 scanning, or (in ; non-interlaced mode) 312/25 and 262/29.97 scanning. ;--------------------------------------------------------------------------- ; feature test switches ;--------------------------------------------------------------------------- ft_sx28 equ 0 ; 0 for SX18/SX20, 1 for SX28 ft_pal_video equ 0 ; 0 for NTSC 525/60, 1 for PAL 625/50 ; (approximate timing only) ; (not well tested) ft_interlace equ 1 ; 1 for interlaced video ft_color equ 0 ; 1 for color burst (NTSC only) ft_serial_input equ 1 ; 1 for normal serial input, ; 0 to omit (when replaced with user ; application code) ft_ser_noninv equ 1 ; 0 for "normal" TTL-level serial, ; mark = low, space = high ; 1 for non-inverted serial (the ; crude resistor-only method) ; mark = high, space = low ft_splash equ 1 ; 1 for splash screen ;--------------------------------------------------------------------------- ; processor definitions and assembler settings ;--------------------------------------------------------------------------- if ft_sx28 processor SX28 else processor SX18 endif radix dec errorlevel -305 ; don't want default destination warning errorlevel -224 ; don't want deprecated instruction warnings, ; since on an SX or PIC16C5X there's no other ; way to set the TRIS or OPTION registers include "sxdefs.inc" device equ pins28+pages4+banks8+oschs+optionx+stackx+bor40+turbo ; for instruction destination argument f equ 1 w equ 0 int_off equ 0xc3 ; RTCC internal clock, prescale by 16, ; RTCC interrupt off, WDT disabled int_on equ 0x83 ; RTCC internal clock, prescale by 16, ; RTCC interrupt on, WDT disabled ;--------------------------------------------------------------------------- ; other includes ;--------------------------------------------------------------------------- include "ascii.inc" ;--------------------------------------------------------------------------- ; video definitions ;--------------------------------------------------------------------------- ; Display size in characters. Note that simply changing these definitions ; won't have the desired effect. rows equ 4 columns equ 20 ; osc = 42.9545 MHz = 12 * color burst ; tCYC = 23.2804 ns ; theoretical total width = 12 * 227.5 = 2730 cycles = 2 * 3 * 5 * 91 = 15 * 182 ; ; The RTCC prescaler can only be set for powers of two, and we need the ; count to be a little under 256, so we use a prescaler of 16 and a divisor ; of 171, for an actual scan line width of 2736 cycles (63.7 us). h equ 2736 ; 63.7 us hsync_pulse_width equ 201 ; 4.7 us equalization_pulse_width equ 98 ; 2.3 us serration_pulse_width equ 201 ; 4.7 us vsync_pulse_width equ (h/2)-serration_pulse_width front_porch_width equ 64 ; 1.5 us back_porch_width equ 193 ; 4.5 us ; safe area = 40 us = 1718 cycles ; 20 chars wide * (5+2) = 139 pixels wide, 12.4 cycles per pixel ; ("rounded" up to 13) ; ; for 4:3 aspect ratio, display should be 90 pixels tall, so make ; a pixel be 3 scan lines. scan_lines_per_vpixel equ 3 vpixels_per_char equ 10 chars_per_row equ 20 if ft_pal_video total_active_lines equ 287 else total_active_lines equ 242 endif active_video_lines equ rows*vpixels_per_char*scan_lines_per_vpixel top_border equ (total_active_lines-active_video_lines)/2 bottom_border equ total_active_lines-(top_border+active_video_lines) ;--------------------------------------------------------------------------- ; I/O port definitions ;--------------------------------------------------------------------------- rxd_bit equ 0 pzt_bit equ 1 txd_bit equ 2 ; not used mode_button_bit equ 3 ; not used #define rxd porta,rxd_bit #define pzt porta,pzt_bit #define txd porta,txd_bit #define mode_button porta,mod_button_bit trisa equ 0x01 ; RxD is our only input inita equ 0x00 trisb equ 0x00 ; all outputs initb equ vid_sync if ft_sx28 trisc equ 0x00 ; all outputs initc equ 0x00 ; drive low endif ;--------------------------------------------------------------------------- ; composite video definitions ;--------------------------------------------------------------------------- vid_port equ portb ; D/A converter ; DAC 0 = ground (sync tip), 255 = 1.25V into 75 ohm load ; one DAC step = 1.25/255 V = 4.902 mV ; there are 140 IRE units to 1.0V, so an IRE unit is 7.143 mV = 1.457 DAC steps vid_sync equ 0 ; -40 IRE vid_blank equ 58 ; 58.29 = 0 IRE vid_black equ 69 ; 69.21 = 7.5 IRE vid_white equ 204 ; 204.00 = 100 IRE vid_max_chroma equ 249 ; 249.17 = 131 IRE burst_amplitude equ 58 ; 58.29 = 40 IREs ;--------------------------------------------------------------------------- ; bell definitions ;--------------------------------------------------------------------------- ; The bell tone is nominally around 500 Hz for 200 ms (100 cycles). ; This works out to a period of 32 scan lines. bell_half_period equ 16 ; lines bell_duration equ 200 ; half-periods ;--------------------------------------------------------------------------- ; serial definitions ;--------------------------------------------------------------------------- ; While serial line idle, sample every scan line. Once start bit is ; detected, delay 6 scan lines, then sample every 13. This results ; in a 1208 bps rate, 0.6% fast. lines_per_serial_sample equ 13 skip_on_ser_rx_mark macro if ft_ser_noninv btfss rxd else btfsc rxd endif endm skip_on_ser_rx_space macro if ft_ser_noninv btfsc rxd else btfss rxd endif endm ;--------------------------------------------------------------------------- ; memory utilization ;--------------------------------------------------------------------------- rambase equ 08h ; start of RAM rombase equ 0000h ; beginning of program romsize equ 0800h chargen equ romsize-384 resetvec equ romsize-1 ; reset vector intvec equ 0000h ; interrupt vector main_page equ 0000h int_page equ 0200h ;--------------------------------------------------------------------------- ; shared variables ;--------------------------------------------------------------------------- org rambase ; start of RAM g_field_count: res 1 ; field down-counter g_mtemp: res 1 ; global temp for main ; "DelM" uses "DelMCnt" in the interupt. Do NOT use DelM or DelMCnt in main! DelMCnt: res 1 ; counter used for cycle delays Five: res 1 Fifteen res 1 ;--------------------------------------------------------------------------- ; variables for main ;--------------------------------------------------------------------------- org 010h main_vars: temp: res 3 char: res 1 ; character being processed escape_state: res 1 ; 0 = normal ; 1 = ESC seen, waiting for 2nd char ; 2 = ESC-Y seen, waiting for <col> ; 3 = ESC-Y <col> seen, waiting for <row> esc_Y_col: res 1 ; cursor cursor_col: res 1 cursor_row: res 1 cursor_loc: res 1 ; for scrolling src_addr equ temp dest_addr equ temp+1 move_count equ temp+2 ;--------------------------------------------------------------------------- ; variables for interrupt ;--------------------------------------------------------------------------- org 030h int_vars: line_type: res 1 ; type of scan line we're working on ; 2 * [0 .. line_types-1] line_count: res 1 ; how many lines of this type to do if ft_color burst_phase: res 1 ; LSB used for burst phase int_temp: res 1 ; general use in interrupt endif line_start: res 1 ; start buffer loc of currently displayed line char_ptr: res 1 ; pointer to currently displayed character chargen_ptr: res 2 ; pointer into character generator inverse_flag: res 1 ; bit 7 indicates current char inverse vpix_cnt: res 1 ; vertical pixel counter scanline_cnt: res 1 ; vertical scan line counter (per pixel) char_cnt: res 1 pixels: res 1 ; pixels of current char ; bell bell_half_cyc: res 1 ; bell half-cycle in lines bell_line_cnt: res 1 ; bell half-cycle down-counter bell_dur_cnt: res 1 ; bell duration ;--------------------------------------------------------------------------- ; variables for serial receive ;--------------------------------------------------------------------------- if ft_serial_input org 050h ser_vars: ser_rx_state: res 1 ser_rx_byte: res 1 ser_rx_samp_cnt: res 1 ser_rx_bit_cnt: res 1 ser_rx_char: res 1 ser_rx_flag: res 1 endif ;--------------------------------------------------------------------------- ; video buffer ;--------------------------------------------------------------------------- ; NOTE: subtract offset of 20h (space) before storing characters into ; video buffer video_buffer equ 070h ; 80 characters, uses last five banks ; *must* start on a bank boundary ; reserve RAM, skipping over banks as needed res_bank_ram macro count local c c set count while c>0 res 1 if ($ & 010h)==0 org $+010h endif c set c-1 endw endm org video_buffer line_0: res_bank_ram columns line_1: res_bank_ram columns line_2: res_bank_ram columns-1 line_2_end: res_bank_ram 1 line_3: res_bank_ram columns-1 line_3_end: res_bank_ram 1 org rombase page interrupt ; 0 goto interrupt ; 1 escape_state_table: movf escape_state,w addwf pcl goto esc_not_seen goto esc_seen goto esc_Y_col_seen goto esc_Y_row_seen control_char_table: movf char,w addwf pcl goto null ; 00 - NUL - null - don't do anything goto null ; 01 - goto null ; 02 - goto null ; 03 - goto null ; 04 - goto null ; 05 - goto null ; 06 - goto bell ; 07 - BEL - bell goto backspace ; 08 - BS - backspace goto null ; 09 - goto line_feed ; 0a - LF - line feed goto null ; 0b - goto form_feed ; 0c - FF - form feed - clear screen goto carriage_return ; 0d - CR - carriage return goto null ; 0e goto null ; 0f goto null ; 10 goto null ; 11 goto null ; 12 goto null ; 13 goto null ; 14 goto null ; 15 goto null ; 16 goto null ; 17 goto null ; 18 goto null ; 19 goto null ; 1a goto escape ; 1b - ESC - escape goto null ; 1c goto null ; 1d goto null ; 1e goto null ; 1f esc_char_table: addwf pcl goto bad_escape ; 40 - @ goto cursor_up ; 41 - A - cursor up goto cursor_down ; 42 - B - cursor down goto cursor_left ; 43 - C - cursor left goto cursor_right ; 44 - D - cursor right goto bad_escape ; 45 - E goto bad_escape ; 46 - F goto bad_escape ; 47 - G goto home_cursor ; 48 - H - cursor home goto rev_line_feed ; 49 - I - reverse line feed (can scroll) goto clear_eop ; 4A - J - clear to end of screen goto clear_eol ; 4B - K - clear to end of line goto bad_escape ; 4C - L goto bad_escape ; 4D - M goto bad_escape ; 4E - N goto bad_escape ; 4F - O goto bad_escape ; 50 - P goto bad_escape ; 51 - Q goto bad_escape ; 52 - R goto bad_escape ; 53 - S goto bad_escape ; 54 - T goto bad_escape ; 55 - U goto bad_escape ; 56 - V goto bad_escape ; 57 - W goto bad_escape ; 58 - X goto esc_Y ; 59 - Y - cursor positioning goto bad_escape ; 5A - Z goto bad_escape ; 5B - [ goto bad_escape ; 5C - \ goto bad_escape ; 5D - ] goto bad_escape ; 5E - ^ goto bad_escape ; 5F - _ show_cursor: movf cursor_loc,w movwf fsr bsf indf,7 bank main_vars return hide_cursor: movf cursor_loc,w movwf fsr bcf indf,7 bank main_vars return ; delay until either the number of fields specified in W have been ; displayed (zero flag set), or a serial character is received ; (zero flag clear) delay_fields: bank ser_vars movwf g_field_count df_loop: if ft_serial_input movf ser_rx_flag ; check serial receive flag btfss status,zf ; character received? goto df_return ; yes, return to caller endif movf g_field_count ; has field count decremented to zero? btfss status,zf goto df_loop ; no, keep looping df_return: bank main_vars return home_cursor: clrf cursor_row carriage_return: clrf cursor_col compute_cursor_loc: movf cursor_row,w ; cursor_loc = 20 * cursor_row movwf cursor_loc bcf status,cf rlf cursor_loc rlf cursor_loc swapf cursor_row,w addwf cursor_loc movf cursor_col,w ; cursor_loc += cursor_col addwf cursor_loc movf cursor_loc,w ; shift high nibble left one bit andlw 0f0h addwf cursor_loc movlw video_buffer ; add in base address addwf cursor_loc null: return ; output a character from W to the display output_char: andlw 07fh ; strip MSB (parity?) and save movwf char goto escape_state_table ; process character esc_not_seen: movf char,w andlw 060h ; is it a control character? btfsc status,zf goto control_char_table ; yes, process and return movf char,w ; is it a DEL xorlw asc_del btfsc status,zf return ; yes, do nothing movf char,w ; fall into printable_char printable_char: movwf g_mtemp ; save character movlw -' ' ; remove offset addwf g_mtemp movf cursor_loc,w ; store character movwf fsr movf g_mtemp,w movwf indf bank main_vars ; fall into cursor_advance cursor_advance: incf cursor_col movf cursor_col,w xorlw columns btfss status,zf goto compute_cursor_loc crlf: clrf cursor_col line_feed: incf cursor_row movf cursor_row,w xorlw rows btfss status,zf goto compute_cursor_loc decf cursor_row ; restore call compute_cursor_loc scroll_up: movlw line_1 movwf src_addr movlw line_0 movwf dest_addr movlw (rows-1)*columns movwf move_count call block_move_up movlw line_3 ; clear freed space movwf temp+1 movlw columns movwf temp goto clear_chars block_move_up: movf src_addr,w movwf fsr movf indf,w movwf g_mtemp bank main_vars incf src_addr bsf src_addr,4 movf dest_addr,w movwf fsr movf g_mtemp,w movwf indf bank main_vars incf dest_addr bsf dest_addr,4 decfsz move_count goto block_move_up return backspace: decf cursor_col btfss cursor_col,7 goto compute_cursor_loc movlw columns-1 movwf cursor_col rev_line_feed: decf cursor_row btfss cursor_row,7 goto compute_cursor_loc incf cursor_row ; restore call compute_cursor_loc scroll_down: movlw line_2_end movwf src_addr movlw line_3_end movwf dest_addr movlw (rows-1)*columns movwf move_count call block_move_down movlw line_0 ; clear freed space movwf temp+1 movlw columns movwf temp goto clear_chars block_move_down: movf src_addr,w movwf fsr movf indf,w movwf g_mtemp bank main_vars decf src_addr btfsc src_addr,4 goto bmd_1 movlw 010h subwf src_addr bmd_1: movf dest_addr,w movwf fsr movf g_mtemp,w movwf indf bank main_vars decf dest_addr btfsc dest_addr,4 goto bmd_2 movlw 010h subwf dest_addr bmd_2: decfsz move_count goto block_move_down return clear_eol: movlw columns ; compute number of chars to clear: movwf temp ; temp := columns - cursor_col movf cursor_col,w subwf temp movf cursor_loc,w movwf temp+1 ; clear temp chars starting at loc temp+1 clear_chars: movlw ' '-020h movwf g_mtemp ; fill temp chars starting at loc temp+1 to value temp+2 fill_chars: movf temp+1,w movwf fsr movf g_mtemp,w movwf indf bank main_vars incf temp+1 bsf temp+1,4 decfsz temp goto fill_chars return form_feed: call home_cursor clear_eop: call clear_eol ; clear to end of current line movlw rows-1 ; compute additional rows to clear: movwf temp ; temp := (rows - 1) - cursor_row movf cursor_row,w subwf temp btfsc status,zf ; any rows to clear? return ; no bcf status,cf ; multiply temp by 20 to get char count rlf temp bcf status,cf rlf temp movf temp,w bcf status,cf rlf temp bcf status,cf rlf temp addwf temp goto fill_chars cursor_up: decf cursor_row movlw rows-1 btfsc cursor_row,7 movwf cursor_row goto compute_cursor_loc cursor_down: incf cursor_row btfsc cursor_row,2 ; hard-coded for 4 rows clrf cursor_row goto compute_cursor_loc cursor_left: decf cursor_col movlw columns-1 btfsc cursor_col,7 movwf cursor_col goto compute_cursor_loc cursor_right: incf cursor_col movf cursor_col,w xorlw columns btfsc status,zf clrf cursor_row goto compute_cursor_loc esc_Y: movlw 2 movwf escape_state bad_escape: return esc_Y_col_seen: movlw ' ' subwf char,w movwf esc_Y_col incf escape_state return escape: incf escape_state return esc_Y_row_seen: movlw (256-' ')-rows ; range check the row (still has ' ' offset) addwf char,w btfsc status,cf goto bad_row movlw ' ' ; move cursor to specified column subwf char,w movwf cursor_row bad_row movlw 256-columns ; range check the column addwf esc_Y_col,w btfsc status,cf goto bad_col movf esc_Y_col,w ; move cursor to specified column movwf cursor_col bad_col: clrf escape_state goto compute_cursor_loc esc_seen: clrf escape_state ; assume only two-char sequence movlw '@' subwf char,w movwf temp andlw 060h ; check for range 40-5F btfss status,zf goto bad_escape movf temp,w goto esc_char_table bell: bank int_vars ; start a bell movlw bell_half_period movwf bell_half_cyc movwf bell_line_cnt movlw bell_duration movwf bell_dur_cnt bank main_vars return reset: mode 0fh ; paranoia movlw int_off option bank main_vars movlw inita movwf porta movlw trisa tris porta movlw initb movwf portb movlw trisb tris portb if ft_sx28 movlw initc movwf portc movlw trisc tris portc endif clrf escape_state call form_feed bank int_vars movlw 5 ; set up for DelM macro movwf Five movlw 15 movwf Fifteen clrf line_type incf line_type,w ; get initial line count page line_dispatch call line_dispatch page $ movwf line_count if ft_serial_input bank ser_vars clrf ser_rx_state movlw 1 movwf ser_rx_samp_cnt clrf ser_rx_flag endif bank main_vars movlw int_on option if ft_splash page splash call splash endif ; call home_cursor main_loop: call show_cursor movlw 30 call delay_fields if ft_serial_input btfss status,zf goto got_char endif call hide_cursor movlw 30 call delay_fields if ft_serial_input btfss status,zf goto got_char endif goto main_loop if ft_serial_input got_char: call hide_cursor ; hide cursor during character processing bank ser_vars ; get character and clear rx flag movf ser_rx_char,w clrf ser_rx_flag bank main_vars call output_char goto main_loop endif ;--------------------------------------------------------------------------- ; interrupt handler ;--------------------------------------------------------------------------- org 0200h include "delm.inc" scanln macro count,function goto function retlw count endm ; table of line type function pointers and counts ; when called for function, takes cycles 58-63 line_dispatch: addwf pcl ; 58 if ft_pal_video ; PAL lines scanln 2,equalization_line ; 624-625 scanln 2,vsync_line ; 1-2 scanln 1,vsync_eq_line ; 3 scanln 2,equalization_line ; 4-5 scanln 17,vblank_line ; 6-22 scanln 1,vblank_black_line ; 23 scanln top_border,black_video_line ; 24-106 scanln active_video_lines,active_video_line ; 107-226 scanln bottom_border-1,black_video_line ; 227-309 if ft_interlace scanln 1,black_video_line ; 310 scanln 2,equalization_line ; 311-312 scanln 1,eq_vsync_line ; 313 scanln 2,vsync_line ; 314-315 scanln 2,equalization_line ; 316-317 scanln 1,eq_vblank_line ; 318 scanln 17,vblank_line ; 319-335 scanln top_border,black_video_line ; 336-418 scanln active_video_lines,active_video_line ; 419-538 scanln bottom_border,black_video_line ; 539-622 endif scanln 1,black_eq_line ; 310 or 623 else ; ; NTSC lines scanln 3,equalization_line ; 1-3 scanln 3,vsync_line ; 4-6 scanln 3,equalization_line ; 7-9 scanln 11,vblank_line ; 10-20 scanln top_border,black_video_line ; 21-81 scanln active_video_lines,active_video_line ; 82-201 scanln bottom_border,black_video_line ; 202-262 if ft_interlace scanln 1,black_eq_line ; 263 scanln 2,equalization_line ; 264-265 scanln 1,eq_vsync_line ; 266 scanln 2,vsync_line ; 267-268 scanln 1,vsync_eq_line ; 269 scanln 2,equalization_line ; 270-271 scanln 1,eq_vblank_line ; 272 scanln 10,vblank_line ; 273-282 scanln 1,vblank_black_line ; 283 scanln top_border,black_video_line ; 284-344 scanln active_video_lines,active_video_line ; 345-464 scanln bottom_border,black_video_line ; 465-525 endif endif line_types equ (($-line_dispatch)-1)/2 if ft_serial_input ; serial input state machine dispatch serial_state_table: movf ser_rx_state,w ; 12 addwf pcl ; 13-15 goto ser_idle ; 16-18 goto ser_data_bit ; 16-18 goto ser_stop_bit ; 16-18 endif bell_48: bcf pzt ; 48 delm 1 ; 49 bell_50: delm 1 ; 50 goto bell_done ; 51-53 interrupt: movlw vid_blank ; 4 start front porch movwf vid_port ; 5 if ft_serial_input bank ser_vars ; 6 decfsz ser_rx_samp_cnt ; 7 goto skip_serial ; 8-10 call serial_state_table ; 9-11 goto serial_done ; 39-41 skip_serial: delm 31 ; 11-41 serial_done: else delm 36 ; 6-41 endif bank int_vars ; 42 movf bell_dur_cnt ; 43 - bell active? btfsc status,zf ; 44 goto bell_48 ; 45-47 - no decfsz bell_line_cnt ; 46 - time to toggle PZT? goto bell_50 ; 47-49 - no movlw 1<<pzt_bit ; 48 - toggle PZT xorwf porta ; 49 decf bell_dur_cnt ; 50 - decrement duration movf bell_half_cyc,w ; 51 - reinit line count movwf bell_line_cnt ; 52 delm 1 ; 53 bell_done: movf line_type,w ; 54 call line_dispatch ; 55-57 decfsz line_count ; any more lines of the current type? goto interrupt_done ; no, done incf line_type ; advance to next line type incf line_type movf line_type,w ; end of field? xorlw line_types*2 btfss status,zf goto get_line_count ; no clrf line_type ; yes, start new field movf g_field_count ; decrement field counter btfss status,zf decf g_field_count get_line_count: incf line_type,w ; new line type, how many lines? call line_dispatch movwf line_count interrupt_done: movlw 256-171 ; all done with this scan line retiw ; at some point within the frame before the first active video line, ; call this subroutine to initialize the pointers display_frame_setup: movlw video_buffer movwf line_start clrf vpix_cnt movlw scan_lines_per_vpixel movwf scanline_cnt return if ft_color burst_l equ vid_blank-(burst_amplitude/2) burst_h equ vid_blank+(burst_amplitude/2) burst_x equ burst_l^burst_h ; burst starts at 228 cycles from horizontal reference point, ; which is 292 cycles from our start of back porch. color_burst: delm 14 ; 270-283 ; $$$ actually, don't toggle burst phase, because our current ; line timing is an integral multiple of the color carrier movlw 0 ; 284 - toggle burst phase xorwf burst_phase ; 285 movlw 18 ; 286 - 18 half-cycles of burst movwf int_temp ; 287 movlw burst_h ; 288 - assume leading edge high btfsc burst_phase,0 ; 289 movlw burst_l ; 290 burst_loop: xorlw burst_x ; 291 399 movwf vid_port ; 292 400 decfsz int_temp ; 293 401 goto burst_loop ; 294-296 402 delm 2 ; 403 movlw vid_blank ; 405 movwf vid_port ; 406 delm 48 ; 407 return ; 455-457 else color_burst: delm 185 ; 270-454 return ; 455-457 endif equalization_line: movlw vid_sync ; 64 - start equalizing pulse movwf vid_port delm equalization_pulse_width-2 movlw vid_blank ; end equalizing pulse movwf vid_port delm ((h/2)-equalization_pulse_width)-2 eq_second_half: movlw vid_sync ; start equalizing pulse movwf vid_port delm equalization_pulse_width-2 movlw vid_blank ; end equalizing pulse movwf vid_port return vsync_line: movlw vid_sync ; 64 - start vsync pulse movwf vid_port delm vsync_pulse_width-2 movlw vid_blank ; end vsync pulse - start serration movwf vid_port delm serration_pulse_width-2 vsync_second_half: movlw vid_sync ; start vsync pulse movwf vid_port delm vsync_pulse_width-2 movlw vid_blank ; end vsync pulse - start serration movwf vid_port return vblank_line: movlw vid_sync ; 64 - start hsync pulse movwf vid_port ; 65 delm hsync_pulse_width-2 ; 66-264 movlw vid_blank ; 265 - end hsync pulse movwf vid_port ; 266 call color_burst ; 267-269 return black_video_line: movlw vid_sync ; 64 - start hsync pulse movwf vid_port ; 65 delm hsync_pulse_width-2 ; 66-264 movlw vid_blank ; 265 - end hsync pulse, start back porch movwf vid_port ; 266 call color_burst ; 267-269 movlw vid_black ; 458 - end back porch, start active video movwf vid_port ; 459 goto display_frame_setup ; $$$ not the best place for this? ; return if ft_interlace|ft_pal_video ; NTSC line 263, PAL line 623 (interlaced), PAL line 310 (non-interlaced) black_eq_line: movlw vid_sync ; 64 - start hsync pulse movwf vid_port ; 65 delm hsync_pulse_width-2 ; 66-264 movlw vid_blank ; 265 - end hsync pulse, start back porch movwf vid_port ; 266 call color_burst ; 267-269 movlw vid_black ; 458 - end back porch, start active video movwf vid_port ; 459 delm ((h/2)-(hsync_pulse_width+back_porch_width))-5 goto eq_second_half endif if ft_interlace ; NTSC line 266, PAL line 313 eq_vsync_line: movlw vid_sync ; 64 - start equalizing pulse movwf vid_port delm equalization_pulse_width-2 movlw vid_blank ; end equalizing pulse movwf vid_port delm ((h/2)-equalization_pulse_width)-5 goto vsync_second_half endif if ft_interlace|ft_pal_video ; NTSC line 269, PAL line 3 vsync_eq_line: movlw vid_sync ; 64 - start vsync pulse movwf vid_port delm vsync_pulse_width-2 movlw vid_blank ; end vsync pulse - start serration movwf vid_port delm serration_pulse_width-5 goto eq_second_half endif if ft_interlace ; NTSC line 272 - like an equalization, but a full line with only one pulse ; PAL line 318 eq_vblank_line: movlw vid_sync ; 64 - start equalizing pulse movwf vid_port delm equalization_pulse_width-2 movlw vid_blank ; end equalizing pulse movwf vid_port return endif if ft_interlace|ft_pal_video ; NTSC line 283, PAL line 23 vblank_black_line: movlw vid_sync ; 64 - start hsync pulse movwf vid_port ; 65 delm hsync_pulse_width-2 ; 66-264 movlw vid_blank ; 265 - end hsync pulse movwf vid_port ; 266 call color_burst ; 267-269 delm ((h/2)+front_porch_width)-458 ; 458-1431 movlw vid_black ; 1432 - start active video movwf vid_port return endif active_video_line: movlw vid_sync ; 64 - start hsync pulse movwf vid_port ; 65 delm hsync_pulse_width-2 ; 66-264 movlw vid_blank ; 265 - end hsync pulse, start back porch movwf vid_port ; 266 call color_burst ; 267-269 movlw vid_black ; 458 - end back porch, start active video movwf vid_port ; 459 btfsc vpix_cnt,3 ; vpixel >= 8? goto active_video_line_done delm 100 movf line_start,w movwf char_ptr movlw chars_per_row+1 movwf char_cnt ; leading dummy character is always blank, allows us to fill ; the pixel pipeline clrf pixels character: ; pixel 0 movlw vid_black ; 0 btfsc pixels,0 ; 1 movlw vid_white ; 2 movwf vid_port ; 3 movf char_ptr,w ; 4 - get next character movwf fsr ; 5 movf indf,w ; 6 bank int_vars ; 7 movwf inverse_flag ; 8 andlw 07fh ; 9 movwf chargen_ptr ; 10 decf char_cnt,w ; 11 - increment buffer pointer btfss status,zf ; 12 - unless we're at end of line incf char_ptr ; 13 - (due to pipeline, we pass through bsf char_ptr,4 ; 14 - here columns+1 times) ; pixel 1 movlw vid_black ; 0 btfsc pixels,1 ; 1 movlw vid_white ; 2 movwf vid_port ; 3 movlw (chargen/4)&0ffh ; 4 - add low part of chargen base addwf chargen_ptr ; 5 movlw (chargen/4)>>8 ; 6 - add high part of chargen base movwf chargen_ptr+1 ; 7 btfsc status,cf ; 8 incf chargen_ptr+1 ; 9 bcf status,cf ; 10 - rotate high bit of vpix_cnt into btfsc vpix_cnt,2 ; 11 - table address bsf status,cf ; 12 rlf chargen_ptr ; 13 rlf chargen_ptr+1 ; 14 ; pixel 2 movlw vid_black ; 0 btfsc pixels,2 ; 1 movlw vid_white ; 2 movwf vid_port ; 3 bcf status,cf ; 4 - rotate next bit of vpix_cnt into btfsc vpix_cnt,1 ; 5 - table address bsf status,cf ; 6 rlf chargen_ptr ; 7 rlf chargen_ptr+1 ; 8 delm 6 ; 9-14 ; pixel 3 movlw vid_black ; 0 btfsc pixels,3 ; 1 movlw vid_white ; 2 movwf vid_port ; 3 DelM 11 ; 4-14 ; pixel 4 movlw vid_black ; 0 btfsc pixels,4 ; 1 movlw vid_white ; 2 movwf vid_port ; 3 movf chargen_ptr+1,w ; 4 movwm ; 5 movf chargen_ptr,w ; 6 iread ; 7-10 movwf pixels ; 11 movmw ; 12 mode 0fh ; 13 movwf chargen_ptr ; 14 - now use chargen_ptr as a temp ; intercharacter space btfsc vpix_cnt,0 ; 0 - get left four pixels into bits 0..3 swapf pixels ; 1 movlw vid_black ; 2 movwf vid_port ; 3 bcf pixels,4 ; 4 btfsc vpix_cnt,0 ; 5 - get rightmost pixel into bit 4 rrf chargen_ptr ; 6 btfsc chargen_ptr,0 ; 7 bsf pixels,4 ; 8 movlw 01fh ; 9 - invert if needed btfsc inverse_flag,7 ; 10 xorwf pixels ; 11 ; $$$ add more inter-character spacing here? decfsz char_cnt ; 12 goto character ; 13-15 active_video_line_done: decfsz scanline_cnt ; more scan lines for this pixel row? return movlw scan_lines_per_vpixel movwf scanline_cnt incf vpix_cnt ; more pixels for this character row? movf vpix_cnt,w xorlw vpixels_per_char btfss status,zf return clrf vpix_cnt movf char_ptr,w ; advance buffer pointer to next character row movwf line_start return ;--------------------------------------------------------------------------- ; serial receive routine ;--------------------------------------------------------------------------- if ft_serial_input ser_idle: movlw 1 ; 19 - sample every line movwf ser_rx_samp_cnt ; 20 skip_on_ser_rx_mark ; 21 - start bit detected? goto ser_ret_25 ; 22-24 - no, return movlw lines_per_serial_sample * 3 / 2 ; 23 movwf ser_rx_samp_cnt ; 24 - skip start bit and sample first data bit ; in middle of bit time movlw 8 ; 25 - set up to receive 8 chars movwf ser_rx_bit_cnt ; 26 clrf ser_rx_byte ; 27 - not needed for 8-bit chars incf ser_rx_state ; 28 incf ser_rx_flag ; 29 - signal main movlw (lines_per_serial_sample * 11)/8 ; 30 - set up for stop bit movwf ser_rx_samp_cnt ; 31 incf ser_rx_state ; 32 - advance to next state goto ser_ret_36 ; 33-35 ser_stop_bit: movlw 1 ; 19 - sample every line movwf ser_rx_samp_cnt ; 20 skip_on_ser_rx_mark ; 21 - line idle? clrf ser_rx_state ; 22 - yes, back to idle ser_ret_23: delm 2 ; 23-24 ser_ret_25: delm 4 ; 25-28 ser_ret_29: delm 3 ; 29-31 ser_ret_32: delm 4 ; 32-35 ser_ret_36: return ; 36-38 endif ;--------------------------------------------------------------------------- ; splash screen ;--------------------------------------------------------------------------- if ft_splash org 400h splash_table: addwf pcl dt asc_bel ; 01234567890123456789 dt "SERVID 0.2 Copyright" dt "2001 Eric Smith and", asc_cr, asc_lf dt "Richard Ottosen", asc_cr, asc_lf dt "(SXLIST challenge) " dt 0 splash: clrf temp+2 splash_loop: movf temp+2,w call splash_table xorlw 0 btfsc status,zf retp page output_char call output_char ; $$$ change to end with retp? page $ incf temp+2 goto splash_loop endif ;--------------------------------------------------------------------------- ; character generator macros ;--------------------------------------------------------------------------- org chargen cg_row1 macro pixels local char local col char set pixels r1_bits set 0 col set 0 while col<5 r1_bits set (r1_bits*2)+(char%10) char set char/10 col set col+1 endw endm cg_row2 macro pixels local char local col char set pixels r2_bits set 0 col set 0 while col<5 r2_bits set (r2_bits*2)+(char%10) char set char/10 col set col+1 endw dw ((r1_bits&010h)<<4)+(r1_bits&0fh)+((r2_bits&010h)<<5)+((r2_bits&0fh)<<4) endm include "charset.inc" org resetvec goto reset end
file: /Techref/scenix/lib/io/dev/video/servid_asm.htm, 32KB, , updated: 2001/10/10 14:48, local time: 2024/12/24 22:17,
3.144.116.34:LOG IN
|
©2024 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions? <A HREF="http://linistepper.com/techref/scenix/lib/io/dev/video/servid_asm.htm"> scenix lib io dev video servid_asm</A> |
Did you find what you needed? |