Peter Verkaik's port of the MASM SERVID code to the SXKey

Code:

; SERVID - Serial video display using Ubicom SX microcontroller
; $Id  servid.asm,v 1.34 2001/01/31 07 25 31 eric Exp $
;****************************************************************
; SX-KEY source mnenomics for SX18 device by Peter Verkaik
; This port uses the same oscillator frequency as the original source
; so it should run directly for NTSC.
; Do not contact the authors of the original source about this conversion
; Instead contact me: peterverkaik@boselectro.nl
;****************************************************************
;
; 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.

device		SX18L,oschs2,turbo,stackx_optionx,carryx	;sx device options
freq		42_954_545					;resonator frequency
id		'-SERVID-'					;code identification
reset		reset_entry					;set reset vector

;Features: 
;
;serial input at 1200 bps 8N1 (eight data bits, no parity, one stop bit), MSB ignored
;monochrome displayo of four lines of twenty characaters 
;1 volt peak-to-peak composite video ouptut into 75 ohm load 
;ASCII character set, 95 displayable characters 
;Subset of VT52 control characters and escape sequences 
;Automatic scrolling ( no extra "4" characters when scrolling ) 
;interlaced or non-interlaced video selectable by conditional assembly 
;approximate RS-170 timing (525/60) 
;approximate PAL timing (625/50) selectable by conditional assembly - maybe.
;PAL timing of an earlier version was only tested in a cursory fashion.
;Since then the line type table for PAL has been rewritten in an attempt to more
;closely meet PAL scanning specifications (e.g., 5 each equalization, vsync,
;equalization pulses per field). However, this newer code has not been tested
;in PAL mode at all. 
;This is a preliminary release. As such, it basically works,
;but there are some known bugs (and probably a lot of unknown ones): 
;
;some escape sequences are acting a bit flaky 
;Supported control codes: 
;
;    $00 Null
;    $07 Bell
;    $08 Backspace
;    $0A Line Feed
;    $0C Form Feed - clear display and home cursor
;    $0D Carriage Return
;    $1B Escape - introduce escape sequence
;    $7F Delete - ignored
;
;    All unrecognized control characters are ignored.
;Supported escape sequences: 
;
;    ESC A - Cursor Up    - wraparound rather than scroll
;    ESC B - Cursor Down  - wraparound rather than scroll
;    ESC C - Cursor Left
;    ESC D - Cursor Right
;
;    ESC H - Cursor Home
;    ESC I - Reverse Line Feed - may scroll
;    ESC J - Erase to End of Screen
;    ESC K - Erase to End of Line
;
;    ESC Y   - Direct cursor addressing, col and row offset by 32
;
;Customization: 
;
;SERVID is designed such that user application code may be added to (or replace)
;the serial character processing. In this release of the code there are 919 words
;of program memory free for a user application, and 21 bytes of RAM free.
;The video generation is entirely interrupt driven, so the user application code
;can run at non-interrupt time without any critical timing constraints. 
;
;Software Requirements: 
;
;As written, SERVID will only assemble with the GPASM assembler, version 0.8.14
;or newer. GPASM is Free Software: 
;http://gpasm.sourceforge.net/ 
;
;Hardware Requirements: 
;
;SERVID requires a processor clock of 42.954545 MHz (12 times the NTSC color burst frequency).
;Note that future versions of SERVID may change to a clock frequency of 57.272727 MHz
;(16 times the NTSC color burst frequency). Digikey offers suitable Epson oscillators
;which they program to customer spec; a suitable 8-pin DIP footprint (4 actual pin) part
;is part number SG-8002DC-PHB-ND. SERVID uses an 8-bit D/A converter on port B to generate
;the video output. A simple R-2R resistor ladder will suffice. 
;
;The serial input should be fed into port RA0. If a conventional EIA-232 receiver
;(MC1489, MAX232, or the like) is used, the variable ft_ser_noninv near the top of
;the servid.asm source file should be set to 0. For a non-inverting serial input
;(such as the crude resistor-only method, see the file SCHEMATIC), ft_ser_noninv
;should be set to 1. 
;
;Bill of Materials 
;All parts but the microcontroller are available from Digikey.
;Digikey part numbers are given except for the microcontroller,
;for which a Mouser part number is given.
;
;http://www.digikey.com/ 
;http://www.mouser.com/ 
;
;            Vendor     Distributor
;Q.  Vendor  Part       Part Number    Description
;--  ------  ---------  -------------  ----------------------------------------
; 1  Ubicom  SX18AC/DP  619-SX18AC/DP  microcontroller, 18-pin plastic DIP
; 1  Epson              SG-8002DC-PHB  preprogrammed oscillator, 42.9545454 MHz
; 1  CTS                761-3-R220     8 * 220 ohm DIP resistor network
; 2  CTS                770-103-R120   5 * 120 ohm SIP res. network, isolated
;
; 1                                    15 ohm 1/8 watt resistor
; 1                                    33K ohm 1/8 watt resistor
; 1                                    180K ohm 1/8 watt resistor
; 1                                    0.1 uF ceramic capacitor
;
; 1                                    BNC or RCA jack for video output
; 1                                    DB25 connector for serial input
; 1                                    5V regulated DC power supply
;
;Schematic 
;Schematic for SERVID
;$Id: SCHEMATIC,v 1.4 2001/01/04 23:52:55 eric Exp $
;
;Copyright 2001 Richard Ottosen
;
;
;                         +5V
;                          |
;          +---------------+
;          |               |
;       0.1 uF             |
;          |               |                                         1.25V p-p
;          |       ----------------                                  Video into
;          V      |                |                                 75 ohms
;                 |  Ubicom    /   |
;                 |  SX18AC   |  7 |--- 220 ohm ---+--------+--- 15 ohm --->
;                 |           |    |               |        |
;           +5V --| MCLR      |    |             120 ohm  120 ohm      +--->
;                 |           |    |               |        |          |
;----------       |           |  6 |--- 220 ohm ---+        |          |
;|42.954545 |     |           |    |               |        V	       V
;|   MHz    |-----| OSC1      |    |            120 ohm
;|Oscillator|     |           |    |               |
; ----------  NC--| OSC2      |  5 |--- 220 ohm ---+
;                 |           |    |               |
;                 |           |    |            120 ohm
;          +------| RTCC      |    |               |
;          |   	  |          /   4 |--- 220 ohm ---+
;          V      |         |      |               |
;                 | Port B <       |            120 ohm
;                 |         |      |               |
;             NC--| PA3      \   3 |--- 220 ohm ---+
;                 |           |    |               |
;             NC--| PA2       |    |            120 ohm
;                 |           |    |               |
;          +------| PA1       |  2 |--- 220 ohm ---+
;          |      |           |    |               |
;         --      |           |    |            120 ohm
;   piezo [] )))  |           |    |               |
;         --      |           |  1 |--- 220 ohm ---+
;          |      |           |    |               |
;          |      |           |    |            120 ohm
;          V      |           |    |               |
;IA-232           |           |  0 |--- 220 ohm ---+
;Input            |            \   |               |
;<----+--- 33K ---| PA0            |            120 ohm
;     |           |                |               |
;   180K           ----------------                |
;     |                    |                    120 ohm
;<----+                    |                       |
;     |                    |                       |
;     V                    V                       V
;---------------------------------------------------------------------------
; feature test switches
;---------------------------------------------------------------------------

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

;==============================================================================
;
;        This program is available from
;
;               Rho Enterprises
;               4100 W. Colfax Ave.
;               Box 33
;               Denver, CO    80204
;
;        Phone  720-359-1467                   Email  info@rhoent.com
;
;                          http //www.rhoent.com/
;
;==============================================================================

;
;SXDEFS.INC by Loren Blaney and Richard Ottosen 14-FEB-2000
;
;Scenix SX Definitions for Microchip MPASM.
;
;REVISIONS
;FEB-23-98, Released.
;MAR-21-98, Added ID label. Corrected XT & HS defs by swapping them.
; Removed ASCII defs. New STATUS defs.
;MAR-27-98, Added PAGEA, BANKA, FCALL, FGOTO, SKIP.
;APR-13-98, Added CSA, CSBE (etc.) macros. Enclose all arguments in parentheses.
;  Indent macros.
;APR-23-98, Changed some comments.
;OCT-4-98, Removed "RADIX DEC", added processor type based on SX FUSEX bits,
;  added Trim bits to FUSEX and other cleanup.   R.O.
;OCT-14-98 BOSC defaults to a "1".
;NOV-4-98, Revised Pins, Trim bits and BOSC in DEVICE equates, removed some
;   inversions.  R.O.
;SEP-11-99, Added warnings and messages to BANK and PAGE macros.  R.O.
;9-JAN-2000, Changed ID bytes to leave unused bits as ones.  R.O.
;12-JAN-2000, Made variables in macros local.  R.O.
;14-FEB-2000, Cleanup.  R.O.

;Define special function registers
;INDF		equ	00h	;used for indirects thru fsr
;RTCC		equ	01h	;real time clock/counter
;PCL		equ	02h	;low 8 bits of PC
;STATUS		equ	03h	;status bits
;FSR		equ	04h	;file select register
;PORTA		equ	05h	;I/O ports
;PORTB		equ	06h	;supports multi-input wake-up (MIWU)
;PORTC		equ	07h

;Define STATUS register bits
CF		equ	0	;carry
DCF		equ	1	;digit carry
ZF		equ	2	;zero
PDF		equ	3	;sleep power down (true low)
TOF		equ	4	;watchdog time out (true low)
;PA0		equ	5	;page select (LSB)
;PA1		equ	6	;page select
;PA2		equ	7	;page select (MSB)

;Define port control registers
;TRISX		equ	0Fh	;tristate (1=input, 0=output)
;PLP		equ	0Eh	;pullup (1=none, 0=20k)
;LVL		equ	0Dh	;level (1=TTL, 0=CMOS)
;ST		equ	0Ch	;Schmitt trigger (1=disabled, 0=enabled)
;WKEN		equ	0Bh	;wake up (1=disabled, 0=enabled)
;WKED		equ	0Ah	;wake up edge (1=falling, 0=rising)
;WKPND		equ	09h	;wake up pending (1=pending, 0=none)
;CMP		equ	08h	;comparator bit  0=result, 6=output, 7=enabled

;Define device symbols for configuration words (FUSE & FUSEX)

;OSCRC		equ	%00	;external RC network (default, inverted)
;OSCHS		equ	%01	;high speed external crystal/resonator
;OSCXT		equ	%10	;normal external crystal/resonator
;OSCLP		equ	%11	;low power external crystal/resonator

;WATCHDOG	equ	1 << 2		;watchdog timer enabled
					; default to disabled
;PROTECT	equ	1 << 3		;code protect enabled (inverted)
					; default is to disable code protect

;OSC4MHZ	equ	%1000 << 4	;internal 4MHz
;OSC2MHZ	equ	%1001 << 4	;internal 2MHz
;OSC1MHZ	equ	%1010 << 4	;internal 1MHz
;OSC500KHZ	equ	%1011 << 4	;internal 500KHz
;OSC250KHZ	equ	%1100 << 4	;internal 250KHz
;OSC125KHZ	equ	%1101 << 4	;internal 125KHz
;OSC62KHZ	equ	%1110 << 4	;internal 62.5KHz
;OSC31KHZ	equ	%1111 << 4	;internal 31.25KHz

;STACKX		equ	1 << 8		;stack is extended to 8 levels (inverted)
					; default to 2 levels
;OPTIONX	equ	1 << 9		;extend option register to 8 bits (inverted)
					; default to 6 bits
;SYNC		equ	1 << 10		;input syncing enabled (inverted)
					; default to disabled
;TURBO		equ	1 << 11		;turbo mode enabled (inverted)
					; default to disabled

;PAGES1		equ	%00 << 12	;default
;PAGES2		equ	%01 << 12
;PAGES4		equ	%10 << 12
;PAGES8		equ	%11 << 12

;BANKS1		equ	%00 << 14	;default
;BANKS2		equ	%01 << 14
;BANKS4		equ	%10 << 14
;BANKS8		equ	%11 << 14

;BOR40		equ	%11 << 16	;4.0V brownout reset
;BOR25		equ	%10 << 16	;2.5
;BOR13		equ	%01 << 16	;1.3
;BOR00		equ	%00 << 16	;disabled (default, inverted)

;CARRYX		equ	1 << 18		;ADDWF & SUBWF use carry input (inverted)
					; default is to ignore carry in

;PRE7		equ	1 << 19		;for changing the preset FUSEX bit 7 (inverted)
					; default is no change

;for modifying factory IRC calibration
;TRIM0		equ	%0000 << 20	;highest frequency
;TRIM3		equ	%0001 << 20
;TRIM6		equ	%0010 << 20
;TRIM9		equ	%0011 << 20	; about 3% per step
;TRIM12		equ	%1000 << 20
;TRIM15		equ	%1001 << 20
;TRIM18		equ	%1010 << 20
;TRIM21		equ	%1011 << 20	;lowest frequency (default)

;PINS18		equ	%0 << 22	;default to 18 pin
;PINS28		equ	%1 << 22

int_off		equ	$c3		; RTCC internal clock, prescale by 16,
					; RTCC interrupt off, WDT disabled

int_on		equ	$83		; RTCC internal clock, prescale by 16,
					; RTCC interrupt on, WDT disabled

;---------------------------------------------------------------------------
; other includes
;---------------------------------------------------------------------------

; ASCII character definitions for serial video display
; $Id  ascii.inc,v 1.1 2001/01/03 20 06 47 eric Exp $
;
; Copyright 2000, 2001 Eric Smith <eric@brouhaha.com>
;
; 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.
;
; Licenses for non-GPL use may be negotiated with the author.

asc_nul		equ	00h
asc_bel		equ	07h
asc_bs		equ	08h
asc_ht		equ	09h
asc_lf		equ	0ah
asc_ff		equ	0ch
asc_cr		equ	0dh
asc_so		equ	0eh
asc_si		equ	0fh
asc_esc		equ	1ah
asc_del		equ	7fh

;---------------------------------------------------------------------------
; 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,954,545 Hz = 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).

int_period			equ	171	; used by interrupt_done
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)

;---------------------------------------------------------------------------
; composite video definitions
;---------------------------------------------------------------------------

vid_port		equ	rb	; 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

;---------------------------------------------------------------------------
; 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

rxd			equ	ra.rxd_bit
pzt			equ	ra.pzt_bit
txd			equ	ra.txd_bit
mode_button		equ	ra.mode_button_bit

trisa			equ	$01	; RxD is our only input
inita			equ	$00

trisb			equ	$00	; all outputs
initb			equ	vid_sync

;---------------------------------------------------------------------------
; 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
noexpand
if ft_ser_noninv
expand
	        sb	rxd
noexpand
else
expand
	        snb	rxd
noexpand
endif
endm

skip_on_ser_rx_space	macro
noexpand
if ft_ser_noninv
expand
	        snb	rxd
noexpand
else
expand
	        sb	rxd
noexpand
endif
endm

;---------------------------------------------------------------------------
; memory utilization
;---------------------------------------------------------------------------

rambase		equ	08h		; start of RAM

rombase		equ	0000h		; beginning of program
romsize		equ	0800h
chargen		equ	romsize-384
intvec		equ	0000h		; interrupt vector

main_page	equ	0000h
int_page	equ	0200h

;---------------------------------------------------------------------------
; shared variables
;---------------------------------------------------------------------------

		org	rambase		; start of RAM

g_field_count	ds	1	; field down-counter

g_mtemp		ds	1	; global temp for main

; "DelM" uses "DelMCnt" in the interupt. Do NOT use DelM or DelMCnt in main!
DelMCnt		ds	1	; counter used for cycle delays
Five		ds	1
Fifteen		ds	1

;---------------------------------------------------------------------------
; variables for main
;---------------------------------------------------------------------------

		org	010h

main_vars

temp		ds	3

char		ds	1	; character being processed
escape_state	ds	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	ds	1

; cursor
cursor_col	ds	1
cursor_row	ds	1
cursor_loc	ds	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	ds	1	; type of scan line we're working on
				;    2 * [0 .. line_types-1]
line_count	ds	1	; how many lines of this type to do

if ft_color
burst_phase	ds	1	; LSB used for burst phase
int_temp	ds	1	; general use in interrupt
endif

line_start	ds	1	; start buffer loc of currently displayed line
char_ptr	ds	1	; pointer to currently displayed character
chargen_ptr	ds	2	; pointer into character generator
inverse_flag	ds	1	; bit 7 indicates current char inverse
vpix_cnt	ds	1	; vertical pixel counter
scanline_cnt	ds	1	; vertical scan line counter (per pixel)
char_cnt	ds	1
pixels		ds	1	; pixels of current char

; bell
bell_half_cyc	ds	1	; bell half-cycle in lines
bell_line_cnt	ds	1	; bell half-cycle down-counter
bell_dur_cnt	ds	1	; bell duration

;---------------------------------------------------------------------------
; variables for serial receive
;---------------------------------------------------------------------------

if ft_serial_input

		org	050h

ser_vars

ser_rx_state		ds	1
ser_rx_byte		ds	1
ser_rx_samp_cnt  	ds	1
ser_rx_bit_cnt		ds	1

ser_rx_char		ds	1
ser_rx_flag		ds	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	1	;res_bank_ram count
noexpand
local1 = \1
rept	local1
expand
	        ds	1
noexpand
if ($ & 010h)=0
expand
	        org	$+010h
noexpand
endif
endr
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
		jmp	interrupt	; 1

escape_state_table
		mov	W, escape_state
		add	PC, W
		jmp	esc_not_seen
		jmp	esc_seen
		jmp	esc_Y_col_seen
		jmp	esc_Y_row_seen

control_char_table
		mov	W, char
		add	PC, W
		jmp	null			; 00 - NUL - null - don't do anything
		jmp	null			; 01 -
		jmp	null			; 02 -
		jmp	null			; 03 -
		jmp	null			; 04 -
		jmp	null			; 05 -
		jmp	null			; 06 -
		jmp	bell			; 07 - BEL - bell
		jmp	backspace		; 08 - BS - backspace
		jmp	null			; 09 -
		jmp	line_feed		; 0a - LF - line feed
		jmp	null			; 0b -
		jmp	form_feed		; 0c - FF - form feed - clear screen
		jmp	carriage_return	        ; 0d - CR - carriage return
		jmp	null			; 0e
		jmp	null			; 0f
		jmp	null			; 10
		jmp	null			; 11
		jmp	null			; 12
		jmp	null			; 13
		jmp	null			; 14
		jmp	null			; 15
		jmp	null			; 16
		jmp	null			; 17
		jmp	null			; 18
		jmp	null			; 19
		jmp	null			; 1a
		jmp	escape			; 1b - ESC - escape
		jmp	null			; 1c
		jmp	null			; 1d
		jmp	null			; 1e
		jmp	null			; 1f

esc_char_table
		add	PC, W
		jmp	bad_escape		; 40 - @
		jmp	cursor_up		; 41 - A - cursor up
		jmp	cursor_down		; 42 - B - cursor down
		jmp	cursor_left		; 43 - C - cursor left
		jmp	cursor_right		; 44 - D - cursor right
		jmp	bad_escape		; 45 - E
		jmp	bad_escape		; 46 - F
		jmp	bad_escape		; 47 - G
		jmp	home_cursor		; 48 - H - cursor home
		jmp	rev_line_feed		; 49 - I - reverse line feed (can scroll)
		jmp	clear_eop		; 4A - J - clear to end of screen
		jmp	clear_eol		; 4B - K - clear to end of line
		jmp	bad_escape		; 4C - L
		jmp	bad_escape		; 4D - M
		jmp	bad_escape		; 4E - N
		jmp	bad_escape		; 4F - O
		jmp	bad_escape		; 50 - P
		jmp	bad_escape		; 51 - Q
		jmp	bad_escape		; 52 - R
		jmp	bad_escape		; 53 - S
		jmp	bad_escape		; 54 - T
		jmp	bad_escape		; 55 - U
		jmp	bad_escape		; 56 - V
		jmp	bad_escape		; 57 - W
		jmp	bad_escape		; 58 - X
		jmp	esc_Y			; 59 - Y - cursor positioning
		jmp	bad_escape		; 5A - Z
		jmp	bad_escape		; 5B - [
		jmp	bad_escape		; 5C - 
		jmp	bad_escape		; 5D - ]
		jmp	bad_escape		; 5E - ^
		jmp	bad_escape		; 5F - _

show_cursor
		mov	W, cursor_loc
		mov	fsr, W
		setb	indf.7
		bank	main_vars
		ret

hide_cursor
		mov	W, cursor_loc
		mov	fsr, W
		clrb	indf.7
		bank	main_vars
		ret

; 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
		mov	g_field_count, W

df_loop
if ft_serial_input

		test	ser_rx_flag	; check serial receive flag
		sb	status.zf	; character received?
		jmp	df_return	; yes, return to caller

endif

		test	g_field_count	; has field count decremented to zero?
		sb	status.zf
		jmp	df_loop		; no, keep looping

df_return
		bank	main_vars
		ret


home_cursor
		clr	cursor_row

carriage_return
		clr	cursor_col

compute_cursor_loc
		mov	W, cursor_row	        ; cursor_loc = 20 * cursor_row
		mov	cursor_loc, W
		clrb	status.cf
		rl	cursor_loc
		rl	cursor_loc
		mov	W, <>cursor_row
		add	cursor_loc, W

		mov	W, cursor_col	        ; cursor_loc += cursor_col
		add	cursor_loc, W

		mov	W, cursor_loc           ; shift high nibble left one bit
		and	W, #0f0h
		add	cursor_loc, W

		mov	W, #video_buffer	; add in base address
		add	cursor_loc, W
null
		ret


; output a character from W to the display
output_char
		and	W, #07fh	        ; strip MSB (parity?) and save
		mov	char, W
		jmp	escape_state_table	; process character


esc_not_seen
		mov	W, char
		and	W, #060h	        ; is it a control character?
		snb	status.zf
		jmp	control_char_table	; yes, process and return

		mov	W, char		        ; is it a DEL
		xor	W, #asc_del
		snb	status.zf
		ret			        ; yes, do nothing

		mov	W, char
		; fall into printable_char

printable_char
		mov	g_mtemp, W	        ; save character

		mov	W, #-' '	        ; remove offset
		add	g_mtemp, W

		mov	W, cursor_loc           ;  store character
		mov	fsr, W
		mov	W, g_mtemp
		mov	indf, W
		bank	 main_vars
		; fall into cursor_advance

cursor_advance
		inc	cursor_col
		mov	W, cursor_col
		xor	W, #columns
		sb	status.zf
		jmp	compute_cursor_loc

crlf
	        clr     cursor_col
line_feed
		inc	cursor_row
		mov	W, cursor_row
		xor	W, #rows
		sb	status.zf
		jmp	compute_cursor_loc
		dec	cursor_row	; restore
		call	compute_cursor_loc

scroll_up
		mov	W, #line_1
		mov	src_addr, W
		mov	W, #line_0
		mov	dest_addr, W
		mov	W, #(rows-1)*columns
		mov	move_count, W
		call	block_move_up

		mov	W, #line_3	          ; clear freed space
		mov	temp+1, W
		mov	W, #columns
		mov	temp, W
		jmp	clear_chars


block_move_up
		mov	W, src_addr
		mov	fsr, W
		mov	W, indf
		mov	g_mtemp, W
		bank	main_vars
		inc	src_addr
		setb	src_addr.4

		mov	W, dest_addr
		mov	fsr, W
		mov	W, g_mtemp
		mov	indf, W
		bank	main_vars
		inc	dest_addr
		setb	dest_addr.4

		decsz	move_count
		jmp	block_move_up

		ret


backspace
		dec	cursor_col
		sb	cursor_col.7
		jmp	compute_cursor_loc
		mov	W, #columns-1
		mov	cursor_col, W

rev_line_feed
		dec	cursor_row
		sb	cursor_row.7
		jmp	compute_cursor_loc
		inc	cursor_row	; restore
		call	compute_cursor_loc

scroll_down
		mov	W, #line_2_end
		mov	src_addr, W
		mov	W, #line_3_end
		mov	dest_addr, W
		mov	W, #(rows-1)*columns
		mov	move_count, W
		call	block_move_down

		mov	W, #line_0 ; clear freed space
		mov	temp+1, W
		mov	W, #columns
		mov	temp, W
		jmp	clear_chars

block_move_down
		mov	W, src_addr
		mov	fsr, W
		mov	W, indf
		mov	g_mtemp, W
		bank	main_vars
		dec	src_addr
		snb	src_addr.4
		jmp	bmd_1
		mov	W, #010h
		sub	src_addr, W

bmd_1
		mov	W, dest_addr
		mov	fsr, W
		mov	W, g_mtemp
		mov	indf, W
		bank	main_vars
		dec	dest_addr
		snb	dest_addr.4
		jmp	bmd_2
		mov	W, #010h
		sub	dest_addr, W

bmd_2
		decsz	move_count
		jmp	block_move_down
		ret


clear_eol
		mov	W, #columns	; compute number of chars to clear
		mov	temp, W		; temp  = columns - cursor_col
		mov	W, cursor_col
		sub	temp, W

		mov	W, cursor_loc
		mov	temp+1, W

; clear temp chars starting at loc temp+1
clear_chars
		mov	W, #' '-020h
		mov	g_mtemp, W

; fill temp chars starting at loc temp+1 to value temp+2
fill_chars
		mov	W, temp+1
		mov	fsr, W
		mov	W, g_mtemp
		mov	indf, W
		bank	main_vars

		inc	temp+1
		setb	temp+1.4
		decsz	temp
		jmp	fill_chars
		ret


form_feed
		call	home_cursor

clear_eop
		call	clear_eol	; clear to end of current line
		mov	W, #rows-1	; compute additional rows to clear
		mov	temp, W		; temp  = (rows - 1) - cursor_row
		mov	W, cursor_row
		sub	temp, W
		snb	status.zf	; any rows to clear?
		ret			; no

		clrb	status.cf	; multiply temp by 20 to get char count
		rl	temp
		clrb	status.cf
		rl	temp
		mov	W, temp
		clrb	status.cf
		rl	temp
		clrb	status.cf
		rl	temp
		add	temp, W

		jmp	fill_chars


cursor_up
		dec	cursor_row
		mov	W, #rows-1
		snb	cursor_row.7
		mov	cursor_row, W
		jmp	compute_cursor_loc

cursor_down
		inc	cursor_row
		snb	cursor_row.2	; hard-coded for 4 rows
		clr	cursor_row
		jmp	compute_cursor_loc

cursor_left
		dec	cursor_col
		mov	W, #columns-1
		snb	cursor_col.7
		mov	cursor_col, W
		jmp	compute_cursor_loc

cursor_right
		inc	cursor_col
		mov	W, cursor_col
		xor	W, #columns
		snb	status.zf
		clr	cursor_row
		jmp	compute_cursor_loc


esc_Y
		mov	W, #2
		mov	escape_state, W
bad_escape
		ret

esc_Y_col_seen
		mov	W, #' '
		mov	W, char-w
		mov	esc_Y_col, W
		inc	escape_state
		ret

escape
		inc	escape_state
		ret

esc_Y_row_seen
		mov	W, #(256-' ')-rows	; range check the row (still has ' ' offset)
		add	W, char
		snb	status.cf
		jmp	bad_row

		mov	W, #' '		; move cursor to specified column
		mov	W, char-w
		mov	cursor_row, W
bad_row

		mov	W, #256-columns	; range check the column
		add	W, esc_Y_col
		snb	status.cf
		jmp	bad_col

		mov	W, esc_Y_col	; move cursor to specified column
		mov	cursor_col, W
bad_col

		clr	escape_state
		jmp	compute_cursor_loc


esc_seen
		clr	escape_state	; assume only two-char sequence
		mov	W, #$40
		mov	W, char-w
		mov	temp, W
		and	W, #060h	; check for range 40-5F
		sb	status.zf
		jmp	bad_escape

		mov	W, temp
		jmp	esc_char_table


bell
		bank	int_vars ; start a bell
		mov	W, #bell_half_period
		mov	bell_half_cyc, W
		mov	bell_line_cnt, W
		mov	W, #bell_duration
		mov	bell_dur_cnt, W
		bank	main_vars
		ret


reset_entry
		mode	0fh	; paranoia

		mov	W, #int_off
		mov	!OPTION, W

		bank	main_vars

		mov	W, #inita
		mov	Ra, W
		mov	W, #trisa
		mov	!ra,w

		mov	W, #initb
		mov	Rb, W
		mov	W, #trisb
		mov	!rb,w

		clr	escape_state
		call	form_feed

		bank	int_vars

		mov	W, #5	; set up for DelM macro
		mov	Five, W
		mov	W, #15
		mov	Fifteen, W

		clr	line_type

		mov	W, ++line_type		; get initial line count
		page	line_dispatch
		call	line_dispatch
		page	$
		mov	line_count, W

if ft_serial_input

		bank	ser_vars

		clr	ser_rx_state
		mov	W, #1
		mov	ser_rx_samp_cnt, W
		clr	ser_rx_flag

endif

		bank	main_vars

		mov	W, #int_on
		mov	!OPTION, W

if ft_splash
		page	splash
		call	splash
endif

                ;call   home_cursor

main_loop
		call	show_cursor
if ft_pal_video
                mov     W, #25
else
		mov	W, #30
endif
		call	delay_fields

if ft_serial_input
		sb	status.zf
		jmp	got_char
endif

		call	hide_cursor
if ft_pal_video
                mov     W, #25
else
		mov	W, #30
endif
		call	delay_fields

if ft_serial_input
		sb	status.zf
		jmp	got_char
endif

		jmp	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
		mov	W, ser_rx_char
		clr	ser_rx_flag
		bank	main_vars

		call	output_char
		jmp	main_loop
endif


;---------------------------------------------------------------------------
; interrupt handler
;---------------------------------------------------------------------------

		org	0200h

; 30-DEC-2000   Eric Smith
; changed for GPASM assembler

;6-JAN-2000 Richard Ottosen

;This routine is for the SX parts in Turbo mode only. It does not matter if the
; Carry fuse is set or clear.
;
;Macro to delay for M number of cycles from 0 through 65535.
;  The macro includes paging for long calls.
;
;Uses the routine "DelW" to do the short delays and uses the variable "DelMCnt"
;  as well for long delays.
;The constants 5 and 15 must be loaded into variables "Five" and "Fifteen"
; before DelM is used.
;
;
DelM	MACRO	1	;DelM _MM
noexpand
local2 = \1
IF (local2 & $FF)=0		;No delay at all
ENDIF
IF (local2 & $FF)=1
		nop		;Delay 1 cycle inline
ENDIF
IF (local2 & $FF)=2
		nop		;Delay 2 cycles inline
		nop
ENDIF
IF (local2 & $FF)=3
		jmp	$+1	;Delay 3 cycles inline
ENDIF
IF (local2 & $FF)=4
		jmp	$+1	;Delay 4 cycles inline
		nop
ENDIF
IF (local2 & $FF)=5
		jmp	$+1	;Delay 5 cycles inline
		nop
		nop
ENDIF
IF (local2 & $FF)=6
		jmp	$+1	;Delay 6 cycles inline
		jmp	$+1
ENDIF
IF (local2 & $FF)=7
		PAGE	Delay6
		call	Delay6	;Delay 7 cycles
ENDIF
IF (local2 & $FF)=8
		PAGE	Delay7
		call	Delay7	;Delay 8 cycles
ENDIF
IF (local2 & $FF)=9
		PAGE	Delay8
		call	Delay8	;Delay 9 cycles
ENDIF
IF (local2 & $FF)=10
		PAGE	Delay9
		call	Delay9	;Delay 10 cycles
ENDIF
IF (local2 & $FF)=11
		PAGE	Delay10
		call	Delay10		;Delay 11 cycles
ENDIF
IF (local2 & $FF)=12
		PAGE	Delay11
		call	Delay11		;Delay 12 cycles
ENDIF
IF (local2 & $FF)=13
		PAGE	Delay12
		call	Delay12		;Delay 13 cycles
ENDIF
IF (local2 & $FF)=14
		PAGE	Delay13
		call	Delay13		;Delay 14 cycles
ENDIF
IF (local2 & $FF)=15
		PAGE	Delay14
		call	Delay14		;Delay 15 cycles
ENDIF
IF (local2 & $FF)=16
		PAGE	Delay15
		call	Delay15		;Delay 16 cycles
ENDIF
IF (local2 & $FF)>16
		mov	W, #((local2-1) & $FF)
		PAGE	DelW
		call	DelW		;Delay for 17 thru 255 cycles
ENDIF
IF (local2 >> 8)<>0
		mov	W, #(local2 >> 8)	;Delay more for greater than 255 cycles
		mov	DelMCnt, W
;_DelMLoop
		mov	W, #251
		PAGE	DelW
		call	DelW
		decsz	DelMCnt
		jmp	$-4			;jmp _DelMLoop
ENDIF
ENDM

; original gpasm source macro by Eric Smith  7/8/96 Hacked by Richard Ottosen 8/8/99
; converted to sx-key mnenomics by Peter Verkaik

;-----------------------------------------------------------------------------
;This version of DelW is for the Scenix parts in Turbo mode. It does not matter
;if the Carry fuse is set or clear.
; DelW delays W cycles, including call, return, and one cycle for the
; mov W, #instruction to set up the count in W
; range is 16..255
;
; For example, the sequence
; mov W, #17
; call DelW
; will take 17 cycles to execute
;-----------------------------------------------------------------------------

; W value on entry		 	  16   17   18   19   20     21     22     23
; Caller's instructions		         ---  ---  ---  ---  ---  -----  -----  -----
;		mov	W, #n		   0    0    0    0    0    0      0      0
;		call	DelW		   1    1    1    1    1    1      1      1

DelW		setb	status.cf	;  4    4    4    4    4    4      4      4
		mov	W, Fifteen-w	;  5    5    5    5    5    5      5      5
_DelWLp		add	W, Five		;  6    6    6    6    6    6 11   7 11   7 11
		sb	status.cf	;  7    7    7    7    7    7 12     12     12
		jmp	_DelWLp		;                           8      8      8
		clrb	status.cf	;  9    9    9    9    9      14     14     14
		add	PC, W		; 10   10   10   10   10      15     15     15
Delay10		nop			;                     13
Delay9		nop			;                13   14
Delay8		nop			;           13   14   15                 18
Delay7		nop			;      13   14   15   16             18     19
Delay6		retp			; 13   14   15   16   17      18     19     20
					; 16   17   18   19   20      21     22     23

Delay15		nop
Delay14		nop
Delay13		nop
Delay12		nop
Delay11		jmp	Delay8


scanln	macro	2	;scanln count,function
expand
		jmp    \2     ;jmp function
		retw   \1     ;retw count
noexpand
endm


; table of line type function pointers and counts
; when called for function, takes cycles 58-63

line_dispatch
		add	PC, W ; 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
		mov	W, ser_rx_state	; 12
		add	PC, W			; 13-15
		jmp	ser_idle		; 16-18
		jmp	ser_data_bit		; 16-18
		jmp	ser_stop_bit		; 16-18
endif


bell_48
		clrb	pzt			; 48
		delm	1			; 49
bell_50
		delm	1			; 50
		jmp	bell_done		; 51-53


interrupt
		mov	W, #vid_blank		; 4 start front porch
		mov	vid_port, W		; 5

if ft_serial_input

		bank	ser_vars		; 6
		decsz	ser_rx_samp_cnt	; 7
		jmp	skip_serial		; 8-10

		call	serial_state_table	; 9-11
		jmp	serial_done		; 39-41

skip_serial
		delm	31			; 11-41
serial_done

else

		delm	36			; 6-41

endif

		bank	int_vars		; 42

		test	bell_dur_cnt		; 43 - bell active?
		snb	status.zf		; 44
		jmp	bell_48			; 45-47 - no

		decsz	bell_line_cnt		; 46 - time to toggle PZT?
		jmp	bell_50			; 47-49 - no

		mov	W, #1<<pzt_bit		; 48 - toggle PZT
		xor	Ra, W			; 49

		dec	bell_dur_cnt		; 50 - decrement duration

		mov	W, bell_half_cyc	; 51 - reinit line count
		mov	bell_line_cnt, W	; 52

		delm	1			; 53
bell_done

		mov	W, line_type		; 54
		call	line_dispatch		; 55-57

		decsz	line_count		; any more lines of the current type?
		jmp	interrupt_done		; no, done

		inc	line_type		; advance to next line type
		inc	line_type
		mov	W, line_type		; end of field?
		xor	W, #line_types*2
		sb	status.zf
		jmp	get_line_count		; no

		clr	line_type		; yes, start new field

		test	g_field_count		; decrement field counter
		sb	status.zf
		dec	g_field_count

get_line_count
		mov	W, ++line_type		; new line type, how many lines?
		call	line_dispatch
		mov	line_count, W

interrupt_done
		mov	W, #256-int_period	; 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
		mov	W, #video_buffer
		mov	line_start, W

		clr	vpix_cnt

		mov	W, #scan_lines_per_vpixel
		mov	scanline_cnt, W

		ret


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
		mov	W, #0		; 284 - toggle burst phase
		xor	burst_phase, W	; 285

		mov	W, #18		; 286 - 18 half-cycles of burst
		mov	int_temp, W	; 287

		mov	W, #burst_h	; 288 - assume leading edge high
		snb	burst_phase.0	; 289
		mov	W, #burst_l	; 290

burst_loop
		xor	W, #burst_x	; 291 399
		mov	vid_port, W	; 292 400
		decsz	int_temp	; 293 401
		jmp	burst_loop	; 294-296 402

		delm	2		; 403
		mov	W, #vid_blank	; 405
		mov	vid_port, W	; 406

		delm	48		; 407
		ret			; 455-457

else

color_burst
		delm	185		; 270-454
		ret			; 455-457

endif


equalization_line
		mov	W, #vid_sync	; 64 - start equalizing pulse
		mov	vid_port, W
		delm	equalization_pulse_width-2

		mov	W, #vid_blank	; end equalizing pulse
		mov	vid_port, W
		delm	((h/2)-equalization_pulse_width)-2

eq_second_half
		mov	W, #vid_sync	; start equalizing pulse
		mov	vid_port, W
		delm	equalization_pulse_width-2

		mov	W, #vid_blank	; end equalizing pulse
		mov	vid_port, W
		ret


vsync_line
		mov	W, #vid_sync	; 64 - start vsync pulse
		mov	vid_port, W
		delm	vsync_pulse_width-2

		mov	W, #vid_blank	; end vsync pulse - start serration
		mov	vid_port, W
		delm	serration_pulse_width-2

vsync_second_half
		mov	W, #vid_sync	; start vsync pulse
		mov	vid_port, W
		delm	vsync_pulse_width-2

		mov	W, #vid_blank	; end vsync pulse - start serration
		mov	vid_port, W
		ret


vblank_line
		mov	W, #vid_sync	; 64 - start hsync pulse
		mov	vid_port, W	; 65
		delm	hsync_pulse_width-2	; 66-264

		mov	W, #vid_blank	; 265 - end hsync pulse
		mov	vid_port, W	; 266
		call	color_burst	; 267-269
		ret


black_video_line
		mov	W, #vid_sync	; 64 - start hsync pulse
		mov	vid_port, W	; 65
		delm	hsync_pulse_width-2	; 66-264

		mov	W, #vid_blank	; 265 - end hsync pulse, start back porch
		mov	vid_port, W	; 266

		call	color_burst	; 267-269

		mov	W, #vid_black	; 458 - end back porch, start active video
		mov	vid_port, W	; 459

		jmp	display_frame_setup	; $$$ not the best place for this?
						; ret


if ft_interlace|ft_pal_video
; NTSC line 263, PAL line 623 (interlaced), PAL line 310 (non-interlaced)
black_eq_line
		mov	W, #vid_sync	; 64 - start hsync pulse
		mov	vid_port, W	; 65
		delm	hsync_pulse_width-2	; 66-264

		mov	W, #vid_blank	; 265 - end hsync pulse, start back porch
		mov	vid_port, W	; 266

		call	color_burst	; 267-269

		mov	W, #vid_black	; 458 - end back porch, start active video
		mov	vid_port, W	; 459
		delm	((h/2)-(hsync_pulse_width+back_porch_width))-5
		jmp	eq_second_half
endif


if ft_interlace
; NTSC line 266, PAL line 313
eq_vsync_line
		mov	W, #vid_sync	; 64 - start equalizing pulse
		mov	vid_port, W
		delm	equalization_pulse_width-2

		mov	W, #vid_blank	; end equalizing pulse
		mov	vid_port, W
		delm	((h/2)-equalization_pulse_width)-5
		jmp	vsync_second_half
endif


if ft_interlace|ft_pal_video
; NTSC line 269, PAL line 3
vsync_eq_line
		mov	W, #vid_sync	; 64 - start vsync pulse
		mov	vid_port, W
		delm	vsync_pulse_width-2

		mov	W, #vid_blank	; end vsync pulse - start serration
		mov	vid_port, W
		delm	serration_pulse_width-5
		jmp	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
		mov	W, #vid_sync	; 64 - start equalizing pulse
		mov	vid_port, W
		delm	equalization_pulse_width-2

		mov	W, #vid_blank	; end equalizing pulse
		mov	vid_port, W
		ret
endif


if ft_interlace|ft_pal_video
; NTSC line 283, PAL line 23
vblank_black_line
		mov	W, #vid_sync	; 64 - start hsync pulse
		mov	vid_port, W	; 65
		delm	hsync_pulse_width-2	; 66-264

		mov	W, #vid_blank	; 265 - end hsync pulse
		mov	vid_port, W	; 266

		call	color_burst	; 267-269

		delm	((h/2)+front_porch_width)-458	; 458-1431

		mov	W, #vid_black	; 1432 - start active video
		mov	vid_port, W
		ret
endif


active_video_line
		mov	W, #vid_sync	; 64 - start hsync pulse
		mov	vid_port, W	; 65
		delm	hsync_pulse_width-2	; 66-264

		mov	W, #vid_blank	; 265 - end hsync pulse, start back porch
		mov	vid_port, W	; 266

		call	color_burst	; 267-269

		mov	W, #vid_black	; 458 - end back porch, start active video
		mov	vid_port, W	; 459

		snb	vpix_cnt.3	; vpixel >= 8?
		jmp	active_video_line_done

		delm	100

		mov	W, line_start
		mov	char_ptr, W

		mov	W, #chars_per_row+1
		mov	char_cnt, W

; leading dummy character is always blank, allows us to fill
; the pixel pipeline
		clr	pixels

character
; pixel 0

		mov	W, #vid_black		; 0
		snb	pixels.0		; 1
		mov	W, #vid_white		; 2
		mov	vid_port, W		; 3

		mov	W, char_ptr		; 4 - get next character
		mov	fsr, W			; 5
		mov	W, indf			; 6
		bank	int_vars		; 7

		mov	inverse_flag,	W	; 8
		and	W, #07fh		; 9
		mov	chargen_ptr, W		; 10

		mov	W, --char_cnt		; 11 - increment buffer pointer
		sb	status.zf		; 12 -   unless we're at end of line
		inc	char_ptr		; 13 -   (due to pipeline, we pass through
		setb	char_ptr.4		; 14 -   here columns+1 times)

; pixel 1

		mov	W, #vid_black		; 0
		snb	pixels.1		; 1
		mov	W, #vid_white		; 2
		mov	vid_port, W		; 3

		mov	W, #(chargen/4)&0ffh	; 4 - add low part of chargen base
		add	chargen_ptr, W		; 5

		mov	W, #(chargen/4)>>8	; 6 - add high part of chargen base
		mov	chargen_ptr+1, W	; 7
		snb	status.cf		; 8
		inc	chargen_ptr+1		; 9

		clrb	status.cf		; 10 - rotate high bit of vpix_cnt into
		snb	vpix_cnt.2		; 11 - table address
		setb	status.cf		; 12
		rl	chargen_ptr		; 13
		rl	chargen_ptr+1		; 14

; pixel 2

		mov	W, #vid_black		; 0
		snb	pixels.2		; 1
		mov	W, #vid_white		; 2
		mov	vid_port, W		; 3

		clrb	status.cf		; 4 - rotate next bit of vpix_cnt into
		snb	vpix_cnt.1		; 5 - table address
		setb	status.cf		; 6
		rl	chargen_ptr		; 7
		rl	chargen_ptr+1		; 8

		delm	6			; 9-14

; pixel 3

		mov	W, #vid_black		; 0
		snb	pixels.3		; 1
		mov	W, #vid_white		; 2
		mov	vid_port, W		; 3

		DelM	11			; 4-14

; pixel 4

		mov	W, #vid_black		; 0
		snb	pixels.4		; 1
		mov	W, #vid_white		; 2
		mov	vid_port, W		; 3

		mov	W, chargen_ptr+1	; 4
		mov     m,w			; 5
		mov	W, chargen_ptr		; 6
		iread				; 7-10
		mov	pixels, W		; 11
		mov     w,m			; 12
		mode	0fh			; 13
		mov	chargen_ptr, W		; 14 - now use chargen_ptr as a temp

; intercharacter space

		snb	vpix_cnt.0		; 0 - get left four pixels into bits 0..3
		swap	pixels			; 1
		mov	W, #vid_black		; 2
		mov	vid_port, W		; 3
		clrb	pixels.4		; 4

		snb	vpix_cnt.0		; 5 - get rightmost pixel into bit 4
		rr	chargen_ptr		; 6
		snb	chargen_ptr.0		; 7
		setb	pixels.4		; 8

		mov	W, #01fh		; 9 - invert if needed
		snb	inverse_flag.7		; 10
		xor	pixels, W		; 11

; $$$ add more inter-character spacing here?

		decsz	char_cnt		; 12
		jmp	character		; 13-15

active_video_line_done

		decsz	scanline_cnt		; more scan lines for this pixel row?
		ret
		mov	W, #scan_lines_per_vpixel
		mov	scanline_cnt, W

		inc	vpix_cnt		; more pixels for this character row?
		mov	W, vpix_cnt
		xor	W, #vpixels_per_char
		sb	status.zf
		ret

		clr	vpix_cnt
		mov	W, char_ptr		; advance buffer pointer to next character row
		mov	line_start, W

		ret


;---------------------------------------------------------------------------
; serial receive routine
;---------------------------------------------------------------------------

if ft_serial_input

ser_idle
		mov	W, #1 			; 19 - sample every line
		mov	ser_rx_samp_cnt, W	; 20

		skip_on_ser_rx_mark		; 21 - start bit detected?
		jmp	ser_ret_25		; 22-24 - no, return

		mov	W, #lines_per_serial_sample * 3 / 2		; 23
		mov	ser_rx_samp_cnt, W 	; 24 - skip start bit and sample first data bit
		; in middle of bit time

		mov	W, #8			; 25 - set up to receive 8 chars
		mov	ser_rx_bit_cnt, W	; 26

		clr	ser_rx_byte		; 27 - not needed for 8-bit chars

		inc	ser_rx_state		; 28 - advance to next state
		jmp	ser_ret_32		; 29-31


ser_data_bit
		clrb	status.cf		; 19 - read a bit
		skip_on_ser_rx_mark		; 20
		setb	status.cf		; 21
		rr	ser_rx_byte		; 22 - rotate into byte

		mov	W, #lines_per_serial_sample	; 23 - set up for next sample
		mov	ser_rx_samp_cnt, W		; 24

		decsz	ser_rx_bit_cnt		; 25 - all data bits read?
		jmp	ser_ret_29		; 26-28 - no

		mov	W, ser_rx_byte		; 27 - move char to buffer
		mov	ser_rx_char, W		; 28
		inc	ser_rx_flag		; 29 - signal main

		mov	W, #(lines_per_serial_sample * 11)/8	; 30 - set up for stop bit
		mov	ser_rx_samp_cnt, W				; 31

		inc	ser_rx_state		; 32 - advance to next state
		jmp	ser_ret_36		; 33-35


ser_stop_bit
		mov	W, #1			; 19 - sample every line
		mov	ser_rx_samp_cnt, W	; 20

		skip_on_ser_rx_mark		; 21 - line idle?
		clr	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	ret				; 36-38

endif


;---------------------------------------------------------------------------
; splash screen
;---------------------------------------------------------------------------

if ft_splash

		org	400h

splash_table
		add	PC, W
		dw	asc_bel
		; 01234567890123456789
		dw	'SERVID 0.2 Copyright'
		dw	'2001 Eric Smith and', asc_cr, asc_lf
		dw	'Richard Ottosen', asc_cr, asc_lf
		dw	'(SXLIST challenge) '
		dw	0


splash
		clr	temp+2
splash_loop
		mov	W, temp+2
		call	splash_table
		xor	W, #0
		snb	status.zf
		retp
		page	output_char
		call	output_char	; $$$ change to end with retp?
		page	$
		inc	temp+2
		jmp	splash_loop

endif

;---------------------------------------------------------------------------
; character generator macros
;---------------------------------------------------------------------------

		org	chargen

cg_row1		macro	1	;cg_row1  pixels
noexpand
char1 = \1
r1_bits = 0
rept 5
r1_bits = (r1_bits*2)+(char1//10)
char1 = char1/10
endr
endm

cg_row2		macro	1	;cg_row2  pixels
noexpand
char2 = \1
r2_bits = 0
rept 5
r2_bits = (r2_bits*2)+(char2//10)
char2 = char2/10
endr
expand
dw ((r1_bits&010h)<<4)+(r1_bits&0fh)+((r2_bits&010h)<<5)+((r2_bits&0fh)<<4)
noexpand
endm

; SERVID character set
; $Id  charset.inc,v 1.4 2001/01/04 04 58 40 eric Exp $
;
; Copyright 2001 Richard Ottosen and Loren Blaney
;
; 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.
;
; Licenses for non-GPL use may be negotiated with the authors.
;
; originally from Bion as a vertical font
; used by Richard Ottosen's Whirlygig
; rotated to horizontal form by Loren Blaney
; munged for SERVID by Richard Ottosen

		cg_row1 00000
		cg_row2 00000
		cg_row1 00000
		cg_row2 00000
		cg_row1 00000
		cg_row2 00000
		cg_row1 00000
		cg_row2 00000	;20h

		cg_row1 00100
		cg_row2 00100
		cg_row1 00100
		cg_row2 00100
		cg_row1 00100
		cg_row2 00000
		cg_row1 00100
		cg_row2 00000 ;21h

		cg_row1 01010
		cg_row2 01010
		cg_row1 01010
		cg_row2 00000
		cg_row1 00000
		cg_row2 00000
		cg_row1 00000
		cg_row2 00000 ;22h

		cg_row1 01010
		cg_row2 01010
		cg_row1 11111
		cg_row2 01010
		cg_row1 11111
		cg_row2 01010
		cg_row1 01010
		cg_row2 00000 ;23h

		cg_row1 00100
		cg_row2 01111
		cg_row1 10100
		cg_row2 01110
		cg_row1 00101
		cg_row2 11110
		cg_row1 00100
		cg_row2 00000 ;24h

		cg_row1 11000
		cg_row2 11001
		cg_row1 00010
		cg_row2 00100
		cg_row1 01000
		cg_row2 10011
		cg_row1 00011
		cg_row2 00000 ;25h

		cg_row1 01000
		cg_row2 10100
		cg_row1 10100
		cg_row2 01000
		cg_row1 10101
		cg_row2 10010
		cg_row1 01101
		cg_row2 00000 ;26h

		cg_row1 00100
		cg_row2 00100
		cg_row1 00100
		cg_row2 00000
		cg_row1 00000
		cg_row2 00000
		cg_row1 00000
		cg_row2 00000 ;27h

		cg_row1 00010
		cg_row2 00100
		cg_row1 01000
		cg_row2 01000
		cg_row1 01000
		cg_row2 00100
		cg_row1 00010
		cg_row2 00000 ;28h

		cg_row1 01000
		cg_row2 00100
		cg_row1 00010
		cg_row2 00010
		cg_row1 00010
		cg_row2 00100
		cg_row1 01000
		cg_row2 00000 ;29h

		cg_row1 00100
		cg_row2 10101
		cg_row1 01110
		cg_row2 00100
		cg_row1 01110
		cg_row2 10101
		cg_row1 00100
		cg_row2 00000 ;2Ah

		cg_row1 00000
		cg_row2 00100
		cg_row1 00100
		cg_row2 11111
		cg_row1 00100
		cg_row2 00100
		cg_row1 00000
		cg_row2 00000 ;2Bh

		cg_row1 00000
		cg_row2 00000
		cg_row1 00000
		cg_row2 00000
		cg_row1 00100
		cg_row2 00100
		cg_row1 01000
		cg_row2 00000 ;2Ch

		cg_row1 00000
		cg_row2 00000
		cg_row1 00000
		cg_row2 11111
		cg_row1 00000
		cg_row2 00000
		cg_row1 00000
		cg_row2 00000 ;2Dh

		cg_row1 00000
		cg_row2 00000
		cg_row1 00000
		cg_row2 00000
		cg_row1 00000
		cg_row2 00000
		cg_row1 00100
		cg_row2 00000 ;2Eh

		cg_row1 00000
		cg_row2 00001
		cg_row1 00010
		cg_row2 00100
		cg_row1 01000
		cg_row2 10000
		cg_row1 00000
		cg_row2 00000 ;2Fh

		cg_row1 01110
		cg_row2 10001
		cg_row1 10011
		cg_row2 10101
		cg_row1 11001
		cg_row2 10001
		cg_row1 01110
		cg_row2 00000 ;30h

		cg_row1 00100
		cg_row2 01100
		cg_row1 00100
		cg_row2 00100
		cg_row1 00100
		cg_row2 00100
		cg_row1 01110
		cg_row2 00000 ;31h

		cg_row1 01110
		cg_row2 10001
		cg_row1 00001
		cg_row2 00110
		cg_row1 01000
		cg_row2 10000
		cg_row1 11111
		cg_row2 00000 ;32h

		cg_row1 11111
		cg_row2 00001
		cg_row1 00010
		cg_row2 00110
		cg_row1 00001
		cg_row2 10001
		cg_row1 01110
		cg_row2 00000 ;33h

		cg_row1 00010
		cg_row2 00110
		cg_row1 01010
		cg_row2 10010
		cg_row1 11111
		cg_row2 00010
		cg_row1 00010
		cg_row2 00000 ;34h

		cg_row1 11111
		cg_row2 10000
		cg_row1 11110
		cg_row2 00001
		cg_row1 00001
		cg_row2 10001
		cg_row1 01110
		cg_row2 00000 ;35h

		cg_row1 00111
		cg_row2 01000
		cg_row1 10000
		cg_row2 11110
		cg_row1 10001
		cg_row2 10001
		cg_row1 01110
		cg_row2 00000 ;36h

		cg_row1 11111
		cg_row2 00001
		cg_row1 00010
		cg_row2 00100
		cg_row1 01000
		cg_row2 01000
		cg_row1 01000
		cg_row2 00000 ;37h

		cg_row1 01110
		cg_row2 10001
		cg_row1 10001
		cg_row2 01110
		cg_row1 10001
		cg_row2 10001
		cg_row1 01110
		cg_row2 00000 ;38h

		cg_row1 01110
		cg_row2 10001
		cg_row1 10001
		cg_row2 01111
		cg_row1 00001
		cg_row2 00010
		cg_row1 11100
		cg_row2 00000 ;39h

		cg_row1 00000
		cg_row2 00000
		cg_row1 00100
		cg_row2 00000
		cg_row1 00100
		cg_row2 00000
		cg_row1 00000
		cg_row2 00000 ;3Ah

		cg_row1 00000
		cg_row2 00000
		cg_row1 00100
		cg_row2 00000
		cg_row1 00100
		cg_row2 00100
		cg_row1 01000
		cg_row2 00000 ;3Bh

		cg_row1 00010
		cg_row2 00100
		cg_row1 01000
		cg_row2 10000
		cg_row1 01000
		cg_row2 00100
		cg_row1 00010
		cg_row2 00000 ;3Ch

		cg_row1 00000
		cg_row2 00000
		cg_row1 11111
		cg_row2 00000
		cg_row1 11111
		cg_row2 00000
		cg_row1 00000
		cg_row2 00000 ;3Dh

		cg_row1 01000
		cg_row2 00100
		cg_row1 00010
		cg_row2 00001
		cg_row1 00010
		cg_row2 00100
		cg_row1 01000
		cg_row2 00000 ;3Eh

		cg_row1 01110
		cg_row2 10001
		cg_row1 00010
		cg_row2 00100
		cg_row1 00100
		cg_row2 00000
		cg_row1 00100
		cg_row2 00000 ;3Fh

		cg_row1 01110
		cg_row2 10001
		cg_row1 10101
		cg_row2 10111
		cg_row1 10110
		cg_row2 10000
		cg_row1 01111
		cg_row2 00000 ;40h

		cg_row1 00100
		cg_row2 01010
		cg_row1 10001
		cg_row2 10001
		cg_row1 11111
		cg_row2 10001
		cg_row1 10001
		cg_row2 00000 ;41h

		cg_row1 11110
		cg_row2 10001
		cg_row1 10001
		cg_row2 11110
		cg_row1 10001
		cg_row2 10001
		cg_row1 11110
		cg_row2 00000 ;42h

		cg_row1 01110
		cg_row2 10001
		cg_row1 10000
		cg_row2 10000
		cg_row1 10000
		cg_row2 10001
		cg_row1 01110
		cg_row2 00000 ;43h

		cg_row1 11110
		cg_row2 10001
		cg_row1 10001
		cg_row2 10001
		cg_row1 10001
		cg_row2 10001
		cg_row1 11110
		cg_row2 00000 ;44h

		cg_row1 11111
		cg_row2 10000
		cg_row1 10000
		cg_row2 11110
		cg_row1 10000
		cg_row2 10000
		cg_row1 11111
		cg_row2 00000 ;45h

		cg_row1 11111
		cg_row2 10000
		cg_row1 10000
		cg_row2 11110
		cg_row1 10000
		cg_row2 10000
		cg_row1 10000
		cg_row2 00000 ;46h

		cg_row1 01111
		cg_row2 10000
		cg_row1 10000
		cg_row2 10000
		cg_row1 10011
		cg_row2 10001
		cg_row1 01111
		cg_row2 00000 ;47h

		cg_row1 10001
		cg_row2 10001
		cg_row1 10001
		cg_row2 11111
		cg_row1 10001
		cg_row2 10001
		cg_row1 10001
		cg_row2 00000 ;48h

		cg_row1 01110
		cg_row2 00100
		cg_row1 00100
		cg_row2 00100
		cg_row1 00100
		cg_row2 00100
		cg_row1 01110
		cg_row2 00000 ;49h

		cg_row1 00001
		cg_row2 00001
		cg_row1 00001
		cg_row2 00001
		cg_row1 00001
		cg_row2 10001
		cg_row1 01110
		cg_row2 00000 ;4Ah

		cg_row1 10001
		cg_row2 10010
		cg_row1 10100
		cg_row2 11000
		cg_row1 10100
		cg_row2 10010
		cg_row1 10001
		cg_row2 00000 ;4Bh

		cg_row1 10000
		cg_row2 10000
		cg_row1 10000
		cg_row2 10000
		cg_row1 10000
		cg_row2 10000
		cg_row1 11111
		cg_row2 00000 ;4Ch

		cg_row1 10001
		cg_row2 11011
		cg_row1 10101
		cg_row2 10101
		cg_row1 10001
		cg_row2 10001
		cg_row1 10001
		cg_row2 00000 ;4Dh

		cg_row1 10001
		cg_row2 10001
		cg_row1 11001
		cg_row2 10101
		cg_row1 10011
		cg_row2 10001
		cg_row1 10001
		cg_row2 00000 ;4Eh

		cg_row1 01110
		cg_row2 10001
		cg_row1 10001
		cg_row2 10001
		cg_row1 10001
		cg_row2 10001
		cg_row1 01110
		cg_row2 00000 ;4Fh

		cg_row1 11110
		cg_row2 10001
		cg_row1 10001
		cg_row2 11110
		cg_row1 10000
		cg_row2 10000
		cg_row1 10000
		cg_row2 00000 ;50h

		cg_row1 01110
		cg_row2 10001
		cg_row1 10001
		cg_row2 10001
		cg_row1 10101
		cg_row2 10010
		cg_row1 01101
		cg_row2 00000 ;51h

		cg_row1 11110
		cg_row2 10001
		cg_row1 10001
		cg_row2 11110
		cg_row1 10100
		cg_row2 10010
		cg_row1 10001
		cg_row2 00000 ;52h

		cg_row1 01110
		cg_row2 10001
		cg_row1 10000
		cg_row2 01110
		cg_row1 00001
		cg_row2 10001
		cg_row1 01110
		cg_row2 00000 ;53h

		cg_row1 11111
		cg_row2 00100
		cg_row1 00100
		cg_row2 00100
		cg_row1 00100
		cg_row2 00100
		cg_row1 00100
		cg_row2 00000 ;54h

		cg_row1 10001
		cg_row2 10001
		cg_row1 10001
		cg_row2 10001
		cg_row1 10001
		cg_row2 10001
		cg_row1 01110
		cg_row2 00000 ;55h

		cg_row1 10001
		cg_row2 10001
		cg_row1 10001
		cg_row2 10001
		cg_row1 10001
		cg_row2 01010
		cg_row1 00100
		cg_row2 00000 ;56h

		cg_row1 10001
		cg_row2 10001
		cg_row1 10001
		cg_row2 10101
		cg_row1 10101
		cg_row2 11011
		cg_row1 10001
		cg_row2 00000 ;57h

		cg_row1 10001
		cg_row2 10001
		cg_row1 01010
		cg_row2 00100
		cg_row1 01010
		cg_row2 10001
		cg_row1 10001
		cg_row2 00000 ;58h

		cg_row1 10001
		cg_row2 10001
		cg_row1 01010
		cg_row2 00100
		cg_row1 00100
		cg_row2 00100
		cg_row1 00100
		cg_row2 00000 ;59h

		cg_row1 11111
		cg_row2 00001
		cg_row1 00010
		cg_row2 00100
		cg_row1 01000
		cg_row2 10000
		cg_row1 11111
		cg_row2 00000 ;5Ah

		cg_row1 11111
		cg_row2 11000
		cg_row1 11000
		cg_row2 11000
		cg_row1 11000
		cg_row2 11000
		cg_row1 11111
		cg_row2 00000 ;5Bh

		cg_row1 00000
		cg_row2 10000
		cg_row1 01000
		cg_row2 00100
		cg_row1 00010
		cg_row2 00001
		cg_row1 00000
		cg_row2 00000 ;5Ch

		cg_row1 11111
		cg_row2 00011
		cg_row1 00011
		cg_row2 00011
		cg_row1 00011
		cg_row2 00011
		cg_row1 11111
		cg_row2 00000 ;5Dh

		cg_row1 00000
		cg_row2 00000
		cg_row1 00100
		cg_row2 01010
		cg_row1 10001
		cg_row2 00000
		cg_row1 00000
		cg_row2 00000 ;5Eh

		cg_row1 00000
		cg_row2 00000
		cg_row1 00000
		cg_row2 00000
		cg_row1 00000
		cg_row2 00000
		cg_row1 11111
		cg_row2 00000 ;5Fh

		cg_row1 01000
		cg_row2 00100
		cg_row1 00010
		cg_row2 00000
		cg_row1 00000
		cg_row2 00000
		cg_row1 00000
		cg_row2 00000 ;60h

		cg_row1 00000
		cg_row2 00000
		cg_row1 01110
		cg_row2 00001
		cg_row1 01111
		cg_row2 10001
		cg_row1 01111
		cg_row2 00000 ;61h

		cg_row1 10000
		cg_row2 10000
		cg_row1 11110
		cg_row2 10001
		cg_row1 10001
		cg_row2 10001
		cg_row1 11110
		cg_row2 00000 ;62h

		cg_row1 00000
		cg_row2 00000
		cg_row1 01111
		cg_row2 10000
		cg_row1 10000
		cg_row2 10000
		cg_row1 01111
		cg_row2 00000 ;63h

		cg_row1 00001
		cg_row2 00001
		cg_row1 01111
		cg_row2 10001
		cg_row1 10001
		cg_row2 10001
		cg_row1 01111
		cg_row2 00000 ;64h

		cg_row1 00000
		cg_row2 00000
		cg_row1 01110
		cg_row2 10001
		cg_row1 11111
		cg_row2 10000
		cg_row1 01111
		cg_row2 00000 ;65h

		cg_row1 00110
		cg_row2 01001
		cg_row1 01000
		cg_row2 11110
		cg_row1 01000
		cg_row2 01000
		cg_row1 01000
		cg_row2 00000 ;66h

		cg_row1 00000
		cg_row2 00000
		cg_row1 01110
		cg_row2 10001
		cg_row1 10001
		cg_row2 01111
		cg_row1 00001
		cg_row2 01110 ;67h

		cg_row1 10000
		cg_row2 10000
		cg_row1 11110
		cg_row2 10001
		cg_row1 10001
		cg_row2 10001
		cg_row1 10001
		cg_row2 00000 ;68h

		cg_row1 00100
		cg_row2 00000
		cg_row1 01100
		cg_row2 00100
		cg_row1 00100
		cg_row2 00100
		cg_row1 01110
		cg_row2 00000 ;69h

		cg_row1 00010
		cg_row2 00000
		cg_row1 00010
		cg_row2 00010
		cg_row1 00010
		cg_row2 00010
		cg_row1 10010
		cg_row2 01100 ;6Ah

		cg_row1 10000
		cg_row2 10000
		cg_row1 10010
		cg_row2 10100
		cg_row1 11000
		cg_row2 10100
		cg_row1 10010
		cg_row2 00000 ;6Bh

		cg_row1 01100
		cg_row2 00100
		cg_row1 00100
		cg_row2 00100
		cg_row1 00100
		cg_row2 00100
		cg_row1 01110
		cg_row2 00000 ;6Ch

		cg_row1 00000
		cg_row2 00000
		cg_row1 11010
		cg_row2 10101
		cg_row1 10101
		cg_row2 10101
		cg_row1 10101
		cg_row2 00000 ;6Dh

		cg_row1 00000
		cg_row2 00000
		cg_row1 11110
		cg_row2 10001
		cg_row1 10001
		cg_row2 10001
		cg_row1 10001
		cg_row2 00000 ;6Eh

		cg_row1 00000
		cg_row2 00000
		cg_row1 01110
		cg_row2 10001
		cg_row1 10001
		cg_row2 10001
		cg_row1 01110
		cg_row2 00000 ;6Fh

		cg_row1 00000
		cg_row2 00000
		cg_row1 11110
		cg_row2 10001
		cg_row1 10001
		cg_row2 11110
		cg_row1 10000
		cg_row2 10000 ;70h

		cg_row1 00000
		cg_row2 00000
		cg_row1 01111
		cg_row2 10001
		cg_row1 10001
		cg_row2 01111
		cg_row1 00001
		cg_row2 00001 ;71h

		cg_row1 00000
		cg_row2 00000
		cg_row1 10110
		cg_row2 11001
		cg_row1 10000
		cg_row2 10000
		cg_row1 10000
		cg_row2 00000 ;72h

		cg_row1 00000
		cg_row2 00000
		cg_row1 01111
		cg_row2 10000
		cg_row1 01110
		cg_row2 00001
		cg_row1 11110
		cg_row2 00000 ;73h

		cg_row1 00100
		cg_row2 00100
		cg_row1 11111
		cg_row2 00100
		cg_row1 00100
		cg_row2 00100
		cg_row1 00011
		cg_row2 00000 ;74h

		cg_row1 00000
		cg_row2 00000
		cg_row1 10001
		cg_row2 10001
		cg_row1 10001
		cg_row2 10001
		cg_row1 01111
		cg_row2 00000 ;75h

		cg_row1 00000
		cg_row2 00000
		cg_row1 10001
		cg_row2 10001
		cg_row1 10001
		cg_row2 01010
		cg_row1 00100
		cg_row2 00000 ;76h

		cg_row1 00000
		cg_row2 00000
		cg_row1 10001
		cg_row2 10101
		cg_row1 10101
		cg_row2 10101
		cg_row1 01010
		cg_row2 00000 ;77h

		cg_row1 00000
		cg_row2 00000
		cg_row1 10001
		cg_row2 01010
		cg_row1 00100
		cg_row2 01010
		cg_row1 10001
		cg_row2 00000 ;78h

		cg_row1 00000
		cg_row2 00000
		cg_row1 10001
		cg_row2 10001
		cg_row1 01010
		cg_row2 00100
		cg_row1 01000
		cg_row2 10000 ;79h

		cg_row1 00000
		cg_row2 00000
		cg_row1 11111
		cg_row2 00010
		cg_row1 00100
		cg_row2 01000
		cg_row1 11111
		cg_row2 00000 ;7Ah

		cg_row1 00110
		cg_row2 01000
		cg_row1 01000
		cg_row2 11000
		cg_row1 01000
		cg_row2 01000
		cg_row1 00110
		cg_row2 00000 ;7Bh

		cg_row1 00100
		cg_row2 00100
		cg_row1 00100
		cg_row2 00000
		cg_row1 00100
		cg_row2 00100
		cg_row1 00100
		cg_row2 00000 ;7Ch

		cg_row1 01100
		cg_row2 00010
		cg_row1 00010
		cg_row2 00011
		cg_row1 00010
		cg_row2 00010
		cg_row1 01100
		cg_row2 00000 ;7Dh

		cg_row1 00000
		cg_row2 00000
		cg_row1 01000
		cg_row2 10101
		cg_row1 00010
		cg_row2 00000
		cg_row1 00000
		cg_row2 00000 ;7Eh

		;cg_row1 11111
		;cg_row2 11111
		;cg_row1 11111
		;cg_row2 11111
		;cg_row1 11111
		;cg_row2 11111
		;cg_row1 11111
		;cg_row2 11111 ;7Fh


end

Interested: