aboutsummaryrefslogtreecommitdiff
path: root/src/col80_modified/cruft
diff options
context:
space:
mode:
Diffstat (limited to 'src/col80_modified/cruft')
-rw-r--r--src/col80_modified/cruft/Makefile45
-rw-r--r--src/col80_modified/cruft/README.txt89
-rw-r--r--src/col80_modified/cruft/autorun.sysbin0 -> 1095 bytes
-rw-r--r--src/col80_modified/cruft/col80.atasm6
-rw-r--r--src/col80_modified/cruft/col80.dasm10
-rw-r--r--src/col80_modified/cruft/col80.info152
-rw-r--r--src/col80_modified/cruft/col80.s21
-rw-r--r--src/col80_modified/cruft/col80.xexbin0 -> 1163 bytes
-rw-r--r--src/col80_modified/cruft/col80_cc65_hack.cfg41
-rw-r--r--src/col80_modified/cruft/col80_dosini_seg.s12
-rw-r--r--src/col80_modified/cruft/col80_entry.s61
-rw-r--r--src/col80_modified/cruft/col80_header_seg.s6
-rw-r--r--src/col80_modified/cruft/col80_include.s50
-rw-r--r--src/col80_modified/cruft/col80_init.s35
-rw-r--r--src/col80_modified/cruft/col80_main.s824
-rw-r--r--src/col80_modified/cruft/col80_main.s.orig895
-rw-r--r--src/col80_modified/cruft/col80_main.xexbin0 -> 1047 bytes
-rw-r--r--src/col80_modified/cruft/col80_orig.xexbin0 -> 1429 bytes
-rw-r--r--src/col80_modified/cruft/col80_runad_seg.s13
-rw-r--r--src/col80_modified/cruft/col80_startaddr.s7
-rw-r--r--src/col80_modified/cruft/col80_startup.s4
-rwxr-xr-xsrc/col80_modified/cruft/dasm2atasm362
-rwxr-xr-xsrc/col80_modified/cruft/dos_20s.atrbin0 -> 92176 bytes
-rw-r--r--src/col80_modified/cruft/font.binbin0 -> 384 bytes
-rw-r--r--src/col80_modified/cruft/font.s54
-rw-r--r--src/col80_modified/cruft/font2xbm.pl47
-rw-r--r--src/col80_modified/cruft/new_font.s48
-rw-r--r--src/col80_modified/cruft/new_font.xbm35
-rwxr-xr-xsrc/col80_modified/cruft/test.atrbin0 -> 92176 bytes
-rw-r--r--src/col80_modified/cruft/xbm2font.pl29
30 files changed, 2846 insertions, 0 deletions
diff --git a/src/col80_modified/cruft/Makefile b/src/col80_modified/cruft/Makefile
new file mode 100644
index 0000000..2152ced
--- /dev/null
+++ b/src/col80_modified/cruft/Makefile
@@ -0,0 +1,45 @@
+
+SRCFILES=col80_dosini_seg.s col80_header_seg.s col80_main.s \
+ col80_runad_seg.s col80_startaddr.s
+
+all: cc65_hack
+ binload -h col80.xex
+
+cc65_hack: $(SRCFILES) col80.s
+ ca65 -t atari -DFUJICHAT col80.s
+ ld65 -C col80_cc65_hack.cfg -o col80_main.xex col80.o
+ ca65 -t atari -DFUJICHAT col80_startup.s
+ ld65 -o col80_startup.xex col80_startup.o
+ cat col80_main.xex col80_startup.xex > col80.xex
+
+
+col80.xex:
+ $(MAKE) dasm_build || $(MAKE) ca65_build || $(MAKE) atasm_build
+
+dasm_build: $(SRCFILES) col80.dasm
+ dasm col80.dasm -f3 -ocol80.xex
+
+ca65_build: $(SRCFILES) col80.s
+ ca65 -t atari col80.s
+ ld65 -t atari -o col80.xex col80.o
+
+atasm_build: $(SRCFILES) col80.atasm
+ perl dasm2atasm col80_header_seg.s col80_header_seg.atasm
+ perl dasm2atasm col80_main.s col80_main.atasm
+ atasm -r -ocol80.xex col80.atasm
+
+check: col80.xex
+ @if cmp col80.xex col80_orig.xex; then \
+ echo "OK: New binary is identical to original" ;\
+ else \
+ echo "BAD: New binary differs from original" ;\
+ fi
+
+clean:
+ rm -f *.o col80_header_seg.atasm col80_main.atasm col80.xex
+
+test:
+ cp dos_20s.atr test.atr
+ cp col80.xex autorun.sys
+ axe -w autorun.sys test.atr
+ atari800 -nobasic test.atr
diff --git a/src/col80_modified/cruft/README.txt b/src/col80_modified/cruft/README.txt
new file mode 100644
index 0000000..720a1cc
--- /dev/null
+++ b/src/col80_modified/cruft/README.txt
@@ -0,0 +1,89 @@
+
+COL80 is a software 80-column driver for the Atari 8-bit computer. It
+uses GRAPHICS 8 with 4x8 pixel character cells, and replaces the OS
+ROM's E: handler.
+
+The file is found in various Atari archives, under various names such
+as COL80.COM, COL80E.COM, COL80HND.COM. The original author and date of
+publication are unknown.
+
+I've disassembled the binary and labelled/commented the source with
+(hopefully) meaningful names. The resulting sources can be reassembled
+with the DASM, ca65, or Atasm assemblers, which will result in a binary
+that compares as identical to the original.
+
+If you have one of the supported assemblers available on your path,
+plus a "make" utility (GNU, BSD, or probably Microsoft's nmake are OK),
+you can use the provided Makefile to rebuild the binary (including your
+own modified version, if you're into that sort of thing).
+
+File list:
+
+README.txt - you're reading it now
+
+Makefile - the usual
+
+col80_main.s - The actual source code for COL80
+
+col80_dosini_seg.s, col80_header_seg.s, col80_runad_seg.s, and
+col80_startaddr.s - Include files, used to build the multi-segment Atari
+binary load format object file.
+
+col80.s, col80.dasm, col80.atasm - Top-level wrappers for the various
+assemblers, which include the other files in the proper order and using
+the proper syntax for the assembler being used.
+
+Modification Ideas:
+
+Implement the missing control character actions. COL80 only does EOL and
+the clear-screen code (125), and the others (arrows, delete/insert/bell)
+are just printed in their graphical form.
+
+The original COL80 loads the driver code at $7A00, so it'll be compatible
+with BASIC, or other cartridge software. I've built a version org'ed at
+$9A00, which works great with disk-only software and gives an extra 8K
+of available RAM (change START_ADDR in col80_startaddr.s).
+
+It should be possible to use 4x7 or 4x6 character cells instead of
+4x8. The font would of course need to be redesigned, and the characters
+would be even smaller than they are now, but this would give you 27 or
+32 rows of text on screen (or more, if you expand the display by a few
+scanlines). With a good green or amber monitor and luma-only output,
+this could be usable.
+
+Instead of inverse video for characters 128-255, could do an expanded
+international character set (ISO Latin-1). Add a UTF-8 parser and you've
+got Unicode on the Atari!
+
+Add a VT100/ANSI escape-sequence parser. Could render actual underlined
+characters, and bold as inverse video. ANSI color codes we can't easily
+do, but could at least strip them out.
+
+Squeeze the driver down to save RAM. Use the standard E: buffer in page 5,
+move the code up so it ends just before the GR.8 display list, eliminate
+the code that installs the handler as X: and checks for the SELECT key
+being held down... get rid of the margin beep. Use RMARGN in zero page
+instead of right_margin at $7C00, move the other COL80 variables to
+page zero. Eliminate the lookup tables, if they can be replaced with
+code that takes up less space and calculates the values on the fly.
+The current driver code is 3 pages long; it might be possible to squish
+it into 2 pages... like, say, page 6 and the cassette buffer, or make it
+auto-relocate itself to MEMLO like Bob-Verter does. Using a 4x6 or 4x7
+font shrinks the font table, too... another thing to do would be to get
+rid of the clear_screen routine (replace with a call to init_graphics_8)
+
+For XL/XE machines, turn COL80 into an OS patch. For modified 400/800
+machines with RAM at $C000-CFFF, move COL80 there. For 130XEs, use an
+extended RAM bank for the driver, and another bank for the screen RAM
+(separate ANTIC/CPU access mode, won't work on most upgraded 800XLs). Just
+keep a tiny stub driver in main RAM, that switches in the driver's bank
+and jumps to it.
+
+Make a COL64 driver (like the SpartaDOS X CON64.SYS). Use 5x8 characters
+for 64 columns (or 5x6 for 64x32). Probably this would count more as
+a rewrite than a modification. The font would have to be stored one
+character per 8 bytes (take up twice as much space), and lots of shifting
+would have to happen when writing to the screen (slow)... Could also
+do 56 columns (7 pixel wide), and actually use the ROM font (just cut
+off the high bit, and for 56x27 also cut off the bottom scanline).
+
diff --git a/src/col80_modified/cruft/autorun.sys b/src/col80_modified/cruft/autorun.sys
new file mode 100644
index 0000000..e62d76d
--- /dev/null
+++ b/src/col80_modified/cruft/autorun.sys
Binary files differ
diff --git a/src/col80_modified/cruft/col80.atasm b/src/col80_modified/cruft/col80.atasm
new file mode 100644
index 0000000..3fdd27a
--- /dev/null
+++ b/src/col80_modified/cruft/col80.atasm
@@ -0,0 +1,6 @@
+
+ .include "col80_startaddr.s"
+ .include "col80_header_seg.atasm"
+ .include "col80_main.atasm"
+ .include "col80_dosini_seg.s"
+ .include "col80_runad_seg.s"
diff --git a/src/col80_modified/cruft/col80.dasm b/src/col80_modified/cruft/col80.dasm
new file mode 100644
index 0000000..b3a1de2
--- /dev/null
+++ b/src/col80_modified/cruft/col80.dasm
@@ -0,0 +1,10 @@
+
+ processor 6502 ; dasm
+
+ .include col80_startaddr.s
+ .include col80_header_seg.s
+ .include col80_main.s
+ .include col80_dosini_seg.s
+
+ .include col80_runad_seg.s
+
diff --git a/src/col80_modified/cruft/col80.info b/src/col80_modified/cruft/col80.info
new file mode 100644
index 0000000..ad821a4
--- /dev/null
+++ b/src/col80_modified/cruft/col80.info
@@ -0,0 +1,152 @@
+global {
+ comments 4;
+ inputname "col80e.raw";
+ outputname "col80e.dasm";
+ startaddr $7A00;
+};
+
+range {
+ start $7A00;
+ end $7BFF;
+ type bytetable;
+};
+
+range {
+ start $7F48;
+ end $7F80;
+ type bytetable;
+};
+
+range {
+ start $7D52;
+ end $7D81;
+ type bytetable;
+};
+
+range {
+ start $7DEA;
+ end $7DF0;
+ type bytetable;
+};
+
+range {
+ start $7EE5;
+ end $7EF0;
+ type addrtable;
+};
+
+LABEL { NAME "s_dev_open_lo"; ADDR $E410; };
+LABEL { NAME "s_dev_open_hi"; ADDR $E411; };
+
+LABEL { NAME "k_dev_get_lo"; ADDR $E424; };
+LABEL { NAME "k_dev_get_hi"; ADDR $E425; };
+
+LABEL { NAME "DOSINI"; ADDR $0C; };
+LABEL { NAME "DOSINI+1"; ADDR $0D; };
+LABEL { NAME "TMPCHR"; ADDR $50; };
+LABEL { NAME "LMARGN"; ADDR $52; };
+LABEL { NAME "DINDEX"; ADDR $57; };
+LABEL { NAME "SAVMSC"; ADDR $58; };
+LABEL { NAME "SAVMSC+1"; ADDR $59; };
+LABEL { NAME "ICAX1Z"; ADDR $2A; };
+LABEL { NAME "ICAX2Z"; ADDR $2B; };
+LABEL { NAME "ROWCRS"; ADDR $54; };
+LABEL { NAME "COLCRS"; ADDR $55; };
+LABEL { NAME "BUFCNT"; ADDR $6B; };
+LABEL { NAME "SSFLAG"; ADDR $02FF; };
+LABEL { NAME "HATABS"; ADDR $031A; };
+LABEL { NAME "CIOV"; ADDR $E456; };
+LABEL { NAME "CONSOL"; ADDR $D01F; };
+LABEL { NAME "AUDF1"; ADDR $D200; };
+LABEL { NAME "AUDC1"; ADDR $D201; };
+LABEL { NAME "ICCOM"; ADDR $0342; };
+LABEL { NAME "ICBAL"; ADDR $0344; };
+LABEL { NAME "ICBAH"; ADDR $0345; };
+LABEL { NAME "COLOR1"; ADDR $02C5; };
+LABEL { NAME "COLOR2"; ADDR $02C6; };
+LABEL { NAME "MEMTOP"; ADDR $02E5; };
+LABEL { NAME "MEMTOP+1"; ADDR $02E6; };
+
+LABEL { NAME "col80e_vector_tab"; ADDR $7EE5; };
+LABEL { NAME "col80e_open-1"; ADDR $7C00; };
+LABEL { NAME "col80e_open"; ADDR $7C01; };
+LABEL { NAME "col80e_close-1"; ADDR $7C3F; };
+LABEL { NAME "col80e_close"; ADDR $7C40; };
+LABEL { NAME "col80e_getbyte-1"; ADDR $7DF1; };
+LABEL { NAME "col80e_getbyte"; ADDR $7DF2; };
+LABEL { NAME "col80e_putbyte-1"; ADDR $7C42; };
+LABEL { NAME "col80e_putbyte"; ADDR $7C43; };
+LABEL { NAME "col80e_init"; ADDR $7EC0; };
+
+LABEL { NAME "screen_ptr_lo"; ADDR $CB; };
+LABEL { NAME "screen_ptr_hi"; ADDR $CC; };
+LABEL { NAME "font_ptr_lo"; ADDR $CD; };
+LABEL { NAME "font_ptr_hi"; ADDR $CE; };
+
+LABEL { NAME "font_data"; ADDR $7A00; };
+LABEL { NAME "lo_nybble_flag"; ADDR $7F48; };
+
+LABEL { NAME "clear_screen"; ADDR $7D0B; };
+LABEL { NAME "regular_char"; ADDR $7C56; };
+LABEL { NAME "check_ssflag"; ADDR $7C7F; };
+LABEL { NAME "dosini_entry_point"; ADDR $7EF4; };
+LABEL { NAME "main_entry_point"; ADDR $7EF7; };
+LABEL { NAME "get_keystroke"; ADDR $7EB7; };
+LABEL { NAME "return_success"; ADDR $7D31; };
+LABEL { NAME "inverse_mask"; ADDR $7F49; };
+LABEL { NAME "not_inverse"; ADDR $7C60; };
+LABEL { NAME "open_s_dev"; ADDR $7C37; };
+LABEL { NAME "init_graphics_8"; ADDR $7C14; };
+LABEL { NAME "not_eol"; ADDR $7C4F; };
+LABEL { NAME "graphics_ok"; ADDR $7C73; };
+LABEL { NAME "setup_screen_ptr"; ADDR $7D34; };
+LABEL { NAME "setup_font_ptr"; ADDR $7CC9; };
+LABEL { NAME "hi_byte_ok"; ADDR $7D4F; };
+LABEL { NAME "row_low_offset_tab"; ADDR $7D52; };
+LABEL { NAME "row_high_offset_tab"; ADDR $7D6A; };
+LABEL { NAME "cls_loop"; ADDR $7D19; };
+LABEL { NAME "write_font_data_odd"; ADDR $7D82; };
+LABEL { NAME "write_font_data_even"; ADDR $7DB9; };
+LABEL { NAME "scroll_screen"; ADDR $7C87; };
+LABEL { NAME "advance_cursor"; ADDR $7CEE; };
+LABEL { NAME "skip_write"; ADDR $7C7C; };
+LABEL { NAME "skip_ninv"; ADDR $7C65; };
+LABEL { NAME "lo_nybble_odd"; ADDR $7D97; };
+LABEL { NAME "hi_nybble_even"; ADDR $7DC8; };
+LABEL { NAME "write_font_done_odd"; ADDR $7DB8; };
+LABEL { NAME "get_font_nybble_odd"; ADDR $7D8C; };
+LABEL { NAME "get_font_nybble_even"; ADDR $7DBD; };
+LABEL { NAME "screen_ptr_ok_odd"; ADDR $7DB0; };
+LABEL { NAME "screen_ptr_ok_even"; ADDR $7DE1; };
+LABEL { NAME "write_font_done_even"; ADDR $7DE9; };
+LABEL { NAME "scanline_offset_tab"; ADDR $7DEA; };
+LABEL { NAME "get_line"; ADDR $7E04; };
+LABEL { NAME "line_buffer_index"; ADDR $7F4A; };
+LABEL { NAME "line_buffer"; ADDR $7F4B; };
+LABEL { NAME "get_next_byte"; ADDR $7DF6; };
+LABEL { NAME "show_cursor"; ADDR $7E0B; };
+LABEL { NAME "keystroke_ok"; ADDR $7E2B; };
+LABEL { NAME "return_key_hit"; ADDR $7E52; };
+LABEL { NAME "check_backs_key"; ADDR $7E32; };
+LABEL { NAME "backs_key_hit"; ADDR $7E71; };
+LABEL { NAME "check_clear_key"; ADDR $7E39; };
+LABEL { NAME "clear_key_hit"; ADDR $7E64; };
+LABEL { NAME "normal_key_hit"; ADDR $7E40; };
+LABEL { NAME "beep"; ADDR $7E8F; };
+LABEL { NAME "beep_delay_x"; ADDR $7E93; };
+LABEL { NAME "beep_delay_y"; ADDR $7E99; };
+LABEL { NAME "buffer_character"; ADDR $7E47; };
+LABEL { NAME "print_space"; ADDR $7EA4; };
+LABEL { NAME "backs_key_done"; ADDR $7E8C; };
+LABEL { NAME "same_line"; ADDR $7E8A; };
+LABEL { NAME "next_hatab_slot"; ADDR $7EC2; };
+LABEL { NAME "register_x_handler"; ADDR $7ED1; };
+LABEL { NAME "no_e_handler"; ADDR $7F30; };
+LABEL { NAME "no_scroll"; ADDR $7D08; };
+LABEL { NAME "next_line"; ADDR $7D0A; };
+LABEL { NAME "font_hi_nybble"; ADDR $7CDB; };
+LABEL { NAME "scroll_line_loop"; ADDR $7C9C; };
+LABEL { NAME "blank_bottom_row"; ADDR $7CAA; };
+LABEL { NAME "blank_loop"; ADDR $7CBA; };
+LABEL { NAME "blank_tail"; ADDR $7CC3; };
+
diff --git a/src/col80_modified/cruft/col80.s b/src/col80_modified/cruft/col80.s
new file mode 100644
index 0000000..334082a
--- /dev/null
+++ b/src/col80_modified/cruft/col80.s
@@ -0,0 +1,21 @@
+
+; ca65 wrapper for building col80
+
+ .setcpu "6502"
+
+ .segment "EXEHDR"
+ .include "col80_startaddr.s"
+ .include "col80_header_seg.s"
+
+ .segment "CODE"
+ .include "col80_main.s"
+
+ .ifndef FUJICHAT
+ .include "col80_dosini_seg.s"
+
+ .segment "AUTOSTRT"
+ .include "col80_runad_seg.s"
+ .endif
+
+ .segment "ZPSAVE"
+ ; nothing to see here, just shutting up ld65's warning
diff --git a/src/col80_modified/cruft/col80.xex b/src/col80_modified/cruft/col80.xex
new file mode 100644
index 0000000..5872c7f
--- /dev/null
+++ b/src/col80_modified/cruft/col80.xex
Binary files differ
diff --git a/src/col80_modified/cruft/col80_cc65_hack.cfg b/src/col80_modified/cruft/col80_cc65_hack.cfg
new file mode 100644
index 0000000..82b2c25
--- /dev/null
+++ b/src/col80_modified/cruft/col80_cc65_hack.cfg
@@ -0,0 +1,41 @@
+FEATURES {
+ STARTADDRESS: default = $2E00;
+}
+SYMBOLS {
+ __STACKSIZE__ = $800; # 2K stack
+ __RESERVED_MEMORY__: value = $0, weak = yes;
+}
+MEMORY {
+ ZP: start = $0082, size = $007E, type = rw, define = yes;
+ HEADER: start = $0000, size = $0006, file = %O;
+ RAM: start = %S, size = $BC20 - __STACKSIZE__ - %S, file = %O;
+ TRAILER: start = $0000, size = $0006, file = %O;
+}
+SEGMENTS {
+ EXEHDR: load = HEADER, type = ro;
+ LOWCODE: load = RAM, type = ro, define = yes, optional = yes;
+ INIT: load = RAM, type = ro, optional = yes;
+ CODE: load = RAM, type = ro, define = yes;
+ RODATA: load = RAM, type = ro;
+ DATA: load = RAM, type = rw;
+ ZPSAVE: load = RAM, type = bss, define = yes;
+ BSS: load = RAM, type = bss, define = yes;
+ HEAP: load = RAM, type = bss, optional = yes; # must sit just below stack
+ ZEROPAGE: load = ZP, type = zp, optional = yes;
+ EXTZP: load = ZP, type = zp, optional = yes;
+ AUTOSTRT: load = TRAILER, type = ro, optional = yes;
+}
+FEATURES {
+ CONDES: segment = INIT,
+ type = constructor,
+ label = __CONSTRUCTOR_TABLE__,
+ count = __CONSTRUCTOR_COUNT__;
+ CONDES: segment = RODATA,
+ type = destructor,
+ label = __DESTRUCTOR_TABLE__,
+ count = __DESTRUCTOR_COUNT__;
+ CONDES: type = interruptor,
+ segment = RODATA,
+ label = __INTERRUPTOR_TABLE__,
+ count = __INTERRUPTOR_COUNT__;
+}
diff --git a/src/col80_modified/cruft/col80_dosini_seg.s b/src/col80_modified/cruft/col80_dosini_seg.s
new file mode 100644
index 0000000..d92e7ed
--- /dev/null
+++ b/src/col80_modified/cruft/col80_dosini_seg.s
@@ -0,0 +1,12 @@
+
+; Second segment of the file loads at $0C (aka DOSINI), and just contains
+; the address of dosini_entry_point
+
+ .ifndef FUJICHAT
+ .word $FFFF ; unnecessary, though the original file had it
+ .endif
+
+ .word $000C ; DOSINI
+ .word $000D
+ .word dosini_entry_point
+
diff --git a/src/col80_modified/cruft/col80_entry.s b/src/col80_modified/cruft/col80_entry.s
new file mode 100644
index 0000000..edf0d96
--- /dev/null
+++ b/src/col80_modified/cruft/col80_entry.s
@@ -0,0 +1,61 @@
+; ----------------------------------------------------------------------------
+; The OS jumps here on warmstart (also, this is the run address in our
+; binary load file)
+
+dosini_entry_point:
+ .ifndef FUJICHAT
+ nop
+ nop
+ nop
+ .endif
+
+main_entry_point:
+ jsr col80_init
+ .ifndef FUJICHAT
+ lda CONSOL
+ and #$04
+ beq no_e_handler
+ .endif
+ lda #$0C
+ sta ICCOM
+ ldx #$00
+ jsr CIOV
+ lda #$58
+ sta font_ptr_lo
+ lda #$03
+ sta ICCOM
+ lda #font_ptr_lo
+ sta ICBAL
+ lda #$00
+ sta ICBAH
+ ldx #$00
+ jsr CIOV
+ ldy #$07
+ lda #<col80_vector_tab
+ sta HATABS,y
+ lda #>col80_vector_tab
+ iny
+ sta HATABS,y
+no_e_handler:
+ lda #<START_ADDRESS
+ sta MEMTOP
+ lda #>START_ADDRESS
+ sta MEMTOP+1
+ .ifdef FUJICHAT
+ ldy #$01
+ rts
+ .else
+ jmp return_success
+ .endif
+
+; ----------------------------------------------------------------------------
+; (when does this actually get called? da65 can't find any references
+; to it, and it's not a run or init address in the binary load file)
+ .ifndef FUJICHAT
+ lda #<dosini_entry_point
+ sta DOSINI
+ lda #>dosini_entry_point
+ sta DOSINI+1
+ jmp main_entry_point
+ .endif
+
diff --git a/src/col80_modified/cruft/col80_header_seg.s b/src/col80_modified/cruft/col80_header_seg.s
new file mode 100644
index 0000000..2f96ad9
--- /dev/null
+++ b/src/col80_modified/cruft/col80_header_seg.s
@@ -0,0 +1,6 @@
+
+ .org START_ADDRESS-6
+ .word $FFFF
+ .word START_ADDRESS
+ .word END_ADDRESS
+
diff --git a/src/col80_modified/cruft/col80_include.s b/src/col80_modified/cruft/col80_include.s
new file mode 100644
index 0000000..943c579
--- /dev/null
+++ b/src/col80_modified/cruft/col80_include.s
@@ -0,0 +1,50 @@
+; ----------------------------------------------------------------------------
+; Zero page labels (OS equates)
+
+DOSINI = $000C
+ICAX1Z = $002A
+ICAX2Z = $002B
+TMPCHR = $0050
+LMARGN = $0052
+ROWCRS = $0054
+COLCRS = $0055
+DINDEX = $0057
+SAVMSC = $0058
+BUFCNT = $006B
+
+; ----------------------------------------------------------------------------
+; Zero page labels (COL80 equates)
+
+screen_ptr_lo = $00CB
+screen_ptr_hi = $00CC
+font_ptr_lo = $00CD
+font_ptr_hi = $00CE
+
+; ----------------------------------------------------------------------------
+; Non-zeropage RAM labels (OS equates)
+
+COLOR1 = $02C5
+COLOR2 = $02C6
+RUNAD = $02E0
+MEMTOP = $02E5
+SSFLAG = $02FF
+HATABS = $031A
+ICCOM = $0342
+ICBAL = $0344
+ICBAH = $0345
+
+; ----------------------------------------------------------------------------
+; Hardware (memory-mapped I/O, OS equates)
+
+CONSOL = $D01F
+AUDF1 = $D200
+AUDC1 = $D201
+
+; ----------------------------------------------------------------------------
+; OS ROM labels
+
+s_dev_open_lo = $E410 ; (not named in OS sources)
+s_dev_open_hi = $E411 ; ""
+k_dev_get_lo = $E424 ; ""
+k_dev_get_hi = $E425 ; ""
+CIOV = $E456 ; Central Input/Output entry point
diff --git a/src/col80_modified/cruft/col80_init.s b/src/col80_modified/cruft/col80_init.s
new file mode 100644
index 0000000..89ccf75
--- /dev/null
+++ b/src/col80_modified/cruft/col80_init.s
@@ -0,0 +1,35 @@
+; ----------------------------------------------------------------------------
+; Initialization callback. The OS will call this on coldstart (or would do,
+; if the driver were in ROM), and also on warmstart (because we stole the
+; DOSINI vector).
+; This routine is also the first thing that gets called by the mainline
+; init code. Its job is to install COL80 in the handler table at HATABS.
+; Actually the handler is first installed as X:, then the main init code
+; fixes this up to E: unless the user is holding down SELECT. This allows
+; the user to toggle between the 40-column ROM E: and COL80 without doing
+; a full reboot. No idea if this was a documented feature or something the
+; author used for development/debugging.
+
+col80_init:
+ ldy #$00
+
+next_hatab_slot:
+ lda HATABS,y
+ beq register_x_handler
+ iny
+ iny
+ iny
+ cpy #$20
+ bcc next_hatab_slot
+ jmp return_success
+
+register_x_handler:
+ lda #$58
+ sta HATABS,y
+ lda #<col80_vector_tab
+ iny
+ sta HATABS,y
+ lda #>col80_vector_tab
+ iny
+ sta HATABS,y
+ jmp return_success
diff --git a/src/col80_modified/cruft/col80_main.s b/src/col80_modified/cruft/col80_main.s
new file mode 100644
index 0000000..0ced210
--- /dev/null
+++ b/src/col80_modified/cruft/col80_main.s
@@ -0,0 +1,824 @@
+; THIS IS A MODIFIED VERSION, for use with FujiChat
+
+; COL80.COM, aka COL80E.COM, aka COL80HND.COM
+; (and probably several other names)
+
+; Original author unknown
+; License unknown
+; Disassembly and comments by Urchlay
+
+; This is a widely-distributed software 80-column driver for the Atari
+; 8-bit computers. It replaces the OS's E: driver, and uses GRAPHICS 8
+; for display, with 4x8 pixel character cells.
+
+; Disassembly was done with da65, with many iterations of "edit the
+; .info file, disassemble again", and the results were tweaked by hand
+; into something assemblable by dasm (and fairly compatible with other
+; assemblers).
+
+
+ .include "col80_include.s"
+
+; START_ADDRESS is defined in col80_startaddr.s
+ .org START_ADDRESS
+
+; ----------------------------------------------------------------------------
+; Start of COL80. The font is stored in packed form. Each group of 8 bytes
+; defines two glyphs: the upper 4 bits of the 8 bytes, taken together,
+; define the bitmap for the first glyph, and the lower 4 bits are the second.
+; Note that the bits that make up a single character are spread across 8
+; bytes, so it's hard to visualize these even if you're used to reading hex
+; dumps.
+
+; The first 2 characters look like:
+
+; .... .O.. ; $04
+; .... .O.. ; $04
+; O.O. .O.. ; $A4
+; OOO. .O.. ; $E4
+; OOO. .OOO ; $E7
+; .O.. .O.. ; $44
+; .... .O.. ; $04
+; .... .O.. ; $04
+
+; These are the ATASCII heart symbol (character code 0) and the ATASCII
+; control-A line-drawing symbol (code 1).
+
+; Note: unlike the ROM font, this font is stored in ATASCII order instead
+; of the standard Atari character order imposed by the hardware. Like
+; the ROM font, inverse characters are not stored here (the bitmaps get
+; inverted by the driver)
+
+font_data:
+ .ifdef FUJICHAT
+ .include "new_font.s"
+ .else
+ ; Low ATASCII graphics symbols (code 0-31)
+ .byte $04,$04,$A4,$E4,$E7,$44,$04,$04
+ .byte $14,$14,$14,$14,$1C,$10,$10,$10
+ .byte $40,$40,$40,$40,$CC,$44,$44,$44
+ .byte $18,$18,$24,$24,$42,$42,$81,$81
+ .byte $10,$10,$30,$30,$73,$73,$F3,$F3
+ .byte $83,$83,$C3,$C3,$E0,$E0,$F0,$F0
+ .byte $CF,$CF,$C0,$C0,$00,$00,$00,$00
+ .byte $00,$00,$00,$00,$0C,$0C,$FC,$FC
+ .byte $00,$00,$00,$40,$A7,$44,$E4,$04
+ .byte $04,$04,$04,$04,$FF,$04,$04,$04
+ .byte $00,$00,$60,$F0,$FF,$6F,$0F,$0F
+ .byte $80,$80,$80,$80,$8F,$84,$84,$84
+ .byte $4C,$4C,$4C,$4C,$FC,$0C,$0C,$0C
+ .byte $40,$4C,$48,$4C,$78,$0C,$06,$00
+ .byte $00,$44,$E4,$44,$4E,$44,$00,$00
+ .byte $00,$24,$42,$FF,$42,$24,$00,$00
+
+ ; Space ! " # etc (codes 32-63)
+ .byte $00,$04,$04,$04,$04,$00,$04,$00
+ .byte $00,$A0,$AA,$AE,$0A,$0E,$0A,$00
+ .byte $00,$40,$68,$82,$44,$28,$C2,$40
+ .byte $00,$C4,$64,$E4,$60,$C0,$40,$00
+ .byte $00,$44,$82,$82,$82,$82,$82,$44
+ .byte $00,$04,$A4,$4E,$E4,$44,$A0,$00
+ .byte $00,$00,$00,$0E,$00,$40,$40,$80
+ .byte $00,$02,$02,$04,$04,$08,$48,$00
+ .byte $00,$E4,$AC,$A4,$A4,$A4,$EE,$00
+ .byte $00,$EE,$22,$22,$EE,$82,$EE,$00
+ .byte $00,$AE,$A8,$AE,$E2,$22,$2E,$00
+ .byte $00,$EE,$82,$E2,$A4,$A4,$E4,$00
+ .byte $00,$EE,$AA,$EA,$AE,$A2,$EE,$00
+ .byte $00,$00,$00,$44,$00,$44,$04,$08
+ .byte $00,$20,$4E,$80,$4E,$20,$00,$00
+ .byte $00,$8C,$42,$22,$44,$80,$04,$00
+
+ ; @ A B C etc (codes 64-95)
+ .byte $00,$6E,$9A,$BA,$BE,$8A,$6A,$00
+ .byte $00,$C6,$A8,$C8,$A8,$A8,$C6,$00
+ .byte $00,$CE,$A8,$AC,$A8,$A8,$CE,$00
+ .byte $00,$E6,$88,$C8,$8A,$8A,$86,$00
+ .byte $00,$AE,$A4,$E4,$A4,$A4,$AE,$00
+ .byte $00,$2A,$2A,$2C,$2A,$2A,$CA,$00
+ .byte $00,$8A,$8E,$8E,$8A,$8A,$EA,$00
+ .byte $00,$C4,$AA,$AA,$AA,$AA,$A4,$00
+ .byte $00,$EE,$AA,$EA,$8A,$8A,$8E,$03
+ .byte $00,$C6,$A8,$AC,$C2,$A2,$AC,$00
+ .byte $00,$EA,$4A,$4A,$4A,$4A,$4E,$00
+ .byte $00,$AA,$AA,$AA,$AE,$AE,$4A,$00
+ .byte $00,$AA,$4A,$4E,$44,$44,$A4,$00
+ .byte $00,$EE,$28,$48,$88,$88,$E8,$0E
+ .byte $00,$8E,$82,$42,$42,$22,$22,$0E
+ .byte $00,$00,$40,$A0,$00,$00,$00,$0F
+
+ ; diamond, lowercase letters, control codes (codes 96-127)
+ .byte $00,$00,$00,$46,$E2,$4E,$0E,$00
+ .byte $00,$80,$80,$C6,$A8,$A8,$C6,$00
+ .byte $00,$20,$20,$6E,$AE,$A8,$6E,$00
+ .byte $00,$00,$C0,$86,$CA,$8E,$82,$0C
+ .byte $00,$80,$84,$80,$C4,$A4,$A4,$00
+ .byte $00,$08,$28,$0A,$2C,$2A,$2A,$C0
+ .byte $00,$40,$40,$4A,$4E,$4A,$4A,$00
+ .byte $00,$00,$00,$CE,$AA,$AA,$AE,$00
+ .byte $00,$00,$00,$C6,$AA,$C6,$82,$82
+ .byte $00,$00,$00,$6E,$88,$86,$8E,$00
+ .byte $00,$00,$40,$EA,$4A,$4A,$6E,$00
+ .byte $00,$00,$00,$AA,$AA,$AE,$4A,$00
+ .byte $00,$00,$00,$AA,$4A,$A6,$A2,$0C
+ .byte $00,$00,$04,$EE,$4E,$84,$EE,$00
+ .byte $40,$4E,$4C,$4E,$4A,$42,$42,$40
+ .byte $00,$28,$6C,$EE,$6C,$28,$00,$00
+ .endif
+
+right_margin:
+ ; Default value is 79 decimal. Unsure why the author didn't use RMARGN at $53
+ .byte $4F
+
+; ----------------------------------------------------------------------------
+; Start of COL80 code.
+
+; Callback for CIO OPEN command.
+
+col80_open:
+ jsr init_graphics_8
+ lda #$00
+ sta ROWCRS
+ sta COLCRS
+ .ifndef FUJICHAT
+ nop
+ nop
+ .endif
+ sta BUFCNT
+ lda #$4F
+ sta right_margin
+ rts
+
+; ----------------------------------------------------------------------------
+; Assembly version of GRAPHICS 8+16 command.
+
+init_graphics_8:
+ lda #$08
+ sta ICAX2Z
+ lda #$0C
+ sta ICAX1Z
+ jsr open_s_dev
+
+ ; Set COL80's default colors
+ lda #$08
+ sta COLOR2
+ .ifndef FUJICHAT
+ nop
+ nop
+ nop
+ .endif
+ lda #$00
+ sta COLOR1
+
+ ; Protect ourselves from BASIC and the OS
+ lda #<START_ADDRESS
+ sta MEMTOP
+ lda #>START_ADDRESS
+ sta MEMTOP+1
+ rts
+
+; ----------------------------------------------------------------------------
+; Call the OPEN vector for the S: device, using the ROM vector table
+; at $E410. The table stores address-minus-one of each routine, which is
+; meant to actually be called via the RTS instruction (standard 6502
+; technique, but confusing the first time you encounter it)
+
+open_s_dev:
+ lda s_dev_open_hi
+ pha
+ lda s_dev_open_lo
+ pha
+ rts
+
+; ----------------------------------------------------------------------------
+; Callback for CIO CLOSE command. Note that the routine does nothing, really
+; (the OS will mark the E: device as being closed, but COL80 doesn't do any
+; cleanup).
+; The SPECIAL and GET STATUS callbacks in col80_vector_tab also point here.
+
+col80_close:
+ jmp return_success
+
+; ----------------------------------------------------------------------------
+; Callback for the internal put-one-byte, used by the OS to implement the
+; CIO PUT RECORD and PUT BYTES commands. This routine's one argument is
+; the byte in the accumulator (the character to print).
+
+; First, the routine checks for the cursor control characters it supports.
+; COL80 only handles the EOL and clear-screen codes; trying to print
+; backspaces, arrows, deletes, inserts, etc just causes their ATASCII
+; graphics character to print instead.
+
+col80_putbyte:
+ ; EOL (decimal 155)?
+ cmp #$9B
+ bne check_clear
+ lda right_margin
+ sta COLCRS
+ jmp skip_write
+
+check_clear:
+ .ifndef FUJICHAT ; save memory by not including clear_screen
+ ; (also, this lets us print the } character)
+ ; Clear (decimal 125)?
+ cmp #$7D
+ bne regular_char
+ jmp clear_screen
+ .endif
+
+ ; See if this is an inverse video char (code >= 128)
+regular_char:
+ tax
+ bpl not_inverse
+ lda #$FF
+ sta inverse_mask
+ bne skip_ninv
+
+not_inverse:
+ lda #$00
+ sta inverse_mask
+
+skip_ninv:
+ txa
+ and #$7F
+ .ifdef FUJICHAT ; mask out low ASCII
+ sec
+ sbc #$20
+ bcs not_low_ascii
+ jmp return_success
+not_low_ascii:
+ .endif
+ sta TMPCHR
+ lda DINDEX
+ cmp #$08
+ beq graphics_ok
+ ; If we're not in GRAPHICS 8 mode, reinitialize ourselves
+ jsr col80_open
+
+graphics_ok:
+ ; Call the routines that actually print the character
+ jsr setup_font_ptr
+ jsr setup_screen_ptr
+ jsr write_font_data
+
+skip_write:
+ ; Move the cursor 1 space to the right. This will
+ ; advance us to the next line if we're at the margin,
+ ; and scroll the screen if needed
+ jsr advance_cursor
+
+check_ssflag:
+ ; The OS keyboard interrupt handler will toggle SSFLAG (start/stop fla
+ ; any time the user presses ctrl-1
+ lda SSFLAG
+ bne check_ssflag
+ jmp return_success
+
+; ----------------------------------------------------------------------------
+; Scroll the screen up one line (8 scanlines). This has to move almost 8K of
+; data, so it's noticeably slower than scrolling the GR.0 text screen.
+
+scroll_screen:
+ lda SAVMSC
+ sta screen_ptr_lo
+ clc
+ adc #$40
+ ; font_ptr_lo is actually being used here as a second pointer into
+ ; screen RAM, instead of its usual use as a pointer into the
+ ; font_data table
+ sta font_ptr_lo
+ lda SAVMSC+1
+ sta screen_ptr_hi
+ adc #$01
+ sta font_ptr_hi
+ ldx #$1D
+ ldy #$00
+
+scroll_line_loop:
+ lda (font_ptr_lo),y
+ sta (screen_ptr_lo),y
+ dey
+ bne scroll_line_loop
+ inc font_ptr_hi
+ inc screen_ptr_hi
+ dex
+ bne scroll_line_loop
+
+blank_bottom_row:
+ lda SAVMSC
+ clc
+ adc #$C0
+ sta screen_ptr_lo
+ lda SAVMSC+1
+ adc #$1C
+ sta screen_ptr_hi
+ lda #$00
+ tay
+
+blank_loop:
+ sta (screen_ptr_lo),y
+ dey
+ bne blank_loop
+ inc screen_ptr_hi
+ ldy #$40
+
+blank_tail:
+ sta (screen_ptr_lo),y
+ dey
+ bpl blank_tail
+ rts
+
+; ----------------------------------------------------------------------------
+; Set up font_ptr_lo/hi to point to the font_data bitmap for the character in
+; TMPCHR. Also sets lo_nybble_flag to let the caller know whether the
+; bitmap is in the upper or lower 4 bits of the bytes pointed to.
+
+setup_font_ptr:
+ lda #$00
+ sta font_ptr_hi
+ sta lo_nybble_flag
+ lda TMPCHR
+ clc
+ ror
+ bcc font_hi_nybble
+ ldx #$FF
+ stx lo_nybble_flag
+
+font_hi_nybble:
+ clc
+ rol
+ rol
+ rol font_ptr_hi
+ rol
+ rol font_ptr_hi
+ adc #<font_data
+ sta font_ptr_lo
+ lda #>font_data
+ adc font_ptr_hi
+ sta font_ptr_hi
+ rts
+
+; ----------------------------------------------------------------------------
+; Move the cursor one space to the right (to the next line if at the margin,
+; and scroll screen if on the last row)
+
+advance_cursor:
+ inc COLCRS
+ lda right_margin
+ cmp COLCRS
+ bcs same_line
+ lda LMARGN
+ sta COLCRS
+ lda ROWCRS
+ ; $17 is 25 decimal, one row below the lowest on the screen
+ cmp #$17
+ bcc no_scroll
+ jsr scroll_screen
+ ; Move to row 24 after scrolling
+ lda #$16
+ sta ROWCRS
+
+no_scroll:
+ inc ROWCRS
+
+same_line:
+ rts
+
+; ----------------------------------------------------------------------------
+; Clear the screen by setting all screen RAM bytes to zero. Slow, but not
+; as slow as scrolling.
+
+ .ifndef FUJICHAT
+clear_screen:
+ lda SAVMSC
+ sta screen_ptr_lo
+ lda SAVMSC+1
+ sta screen_ptr_hi
+ ldy #$00
+ ldx #$1D
+ lda #$00
+
+cls_loop:
+ sta (screen_ptr_lo),y
+ dey
+ bne cls_loop
+ inc screen_ptr_hi
+ dex
+ bne cls_loop
+ jsr blank_bottom_row
+ lda LMARGN
+ sta COLCRS
+ lda #$00
+ sta ROWCRS
+ ; redundant JMP
+ jmp return_success
+ .endif
+
+; ----------------------------------------------------------------------------
+; CIO expects the Y register to contain a status code.
+; 1 means success (no error). Lots of COL80's routines
+; jump here.
+
+return_success:
+ ldy #$01
+ rts
+
+; ----------------------------------------------------------------------------
+; Set screen_ptr_lo/hi to point to the address of the first byte of graphics
+; data at the current cursor position.
+
+setup_screen_ptr:
+ ldy ROWCRS
+ lda SAVMSC
+ clc
+ adc row_low_offset_tab,y
+ sta screen_ptr_lo
+ lda SAVMSC+1
+ adc row_high_offset_tab,y
+ sta screen_ptr_hi
+ lda COLCRS
+ lsr
+ clc
+ adc screen_ptr_lo
+ bcc hi_byte_ok
+ inc screen_ptr_hi
+
+hi_byte_ok:
+ sta screen_ptr_lo
+ rts
+
+; ----------------------------------------------------------------------------
+; Tables of offsets for setup_screen_ptr, to avoid doing multiplication at
+; runtime (the 6502 lacks a MUL instruction, so it's slow...)
+
+row_low_offset_tab:
+ .byte $00,$40,$80,$C0,$00,$40,$80,$C0
+ .byte $00,$40,$80,$C0,$00,$40,$80,$C0
+ .byte $00,$40,$80,$C0,$00,$40,$80,$C0
+
+row_high_offset_tab:
+ .byte $00,$01,$02,$03,$05,$06,$07,$08
+ .byte $0A,$0B,$0C,$0D,$0F,$10,$11,$12
+ .byte $14,$15,$16,$17,$19,$1A,$1B,$1C
+
+; ----------------------------------------------------------------------------
+; Copy pixel data from the font table to screen RAM.
+; font_ptr_lo/hi must point to the correct character, and screen_ptr_lo/hi
+; must point to the correct screen address for the current cursor position.
+; This routine has separate execution paths for even- and odd-numbered
+; cursor positions, since each byte of screen RAM holds data for two
+; adjacent characters (and when printing to one of them, the other needs
+; to be left undisturbed!)
+
+write_font_data:
+ lda COLCRS
+ clc
+ ror
+ bcc write_font_data_even
+ ldx #$00
+ ldy #$00
+
+get_font_nybble_odd:
+ lda (font_ptr_lo),y
+ bit lo_nybble_flag
+ bne lo_nybble_odd
+ ; glyph we want is stored in top 4 bits of font byte,
+ ; shift it down to the bottom 4 bits
+ lsr
+ lsr
+ lsr
+ lsr
+
+lo_nybble_odd:
+ eor inverse_mask
+ and #$0F
+ sta TMPCHR
+ ldy scanline_offset_tab,x
+ lda (screen_ptr_lo),y
+ and #$F0
+ ora TMPCHR
+ sta (screen_ptr_lo),y
+ inx
+ cpx #$07
+ bne screen_ptr_ok_odd
+ inc screen_ptr_hi
+
+screen_ptr_ok_odd:
+ cpx #$08
+ beq write_font_done_odd
+ txa
+ tay
+ bne get_font_nybble_odd
+
+write_font_done_odd:
+ rts
+
+; ----------------------------------------------------------------------------
+; Write data to even-numbered columns, very similar to the above
+
+write_font_data_even:
+ ldx #$00
+ ldy #$00
+
+get_font_nybble_even:
+ lda (font_ptr_lo),y
+ bit lo_nybble_flag
+ beq hi_nybble_even
+ asl
+ asl
+ asl
+ asl
+
+hi_nybble_even:
+ eor inverse_mask
+ and #$F0
+ sta TMPCHR
+ ldy scanline_offset_tab,x
+ lda (screen_ptr_lo),y
+ and #$0F
+ ora TMPCHR
+ sta (screen_ptr_lo),y
+ inx
+ cpx #$07
+ bne screen_ptr_ok_even
+ inc screen_ptr_hi
+
+screen_ptr_ok_even:
+ cpx #$08
+ beq write_font_done_even
+ txa
+ tay
+ bne get_font_nybble_even
+
+write_font_done_even:
+ rts
+
+; ----------------------------------------------------------------------------
+
+scanline_offset_tab:
+ .byte $00,$28,$50,$78,$A0,$C8,$F0,$18
+
+; ----------------------------------------------------------------------------
+; Callback for the internal get-one-byte, used by the OS to implement the
+; CIO GET RECORD and GET BYTES commands. This routine takes no arguments,
+; and returns the read byte in the accumulator.
+
+; Internally, COL80 maintains a line buffer. Each time col80_getbyte is
+; called, it returns the next character in the buffer. If the buffer's
+; empty (or if the last call returned the last character), a new line
+; of input is read from the user (and the first character is returned).
+; This is exactly how the OS E: device works.
+
+col80_getbyte:
+ lda BUFCNT
+ beq get_line
+
+get_next_byte:
+ ldx line_buffer_index
+ lda line_buffer,x
+ dec BUFCNT
+ inc line_buffer_index
+ jmp return_success
+
+; ----------------------------------------------------------------------------
+; Get a line of input from the user, terminated by the Return key.
+
+get_line:
+ lda #$00
+ sta BUFCNT
+ sta line_buffer_index
+
+show_cursor:
+ .ifdef FUJICHAT
+ lda #$00
+ .else
+ lda #$20
+ .endif
+ sta TMPCHR
+ lda #$FF
+ sta inverse_mask
+ jsr setup_font_ptr
+ jsr setup_screen_ptr
+ jsr write_font_data
+ jsr get_keystroke
+ cpy #$01
+ beq keystroke_ok
+ .ifdef FUJICHAT
+ dey ; yes, we really care about 1-byte optimizations
+ .else
+ ldy #$00
+ .endif
+ sty line_buffer_index
+ sty BUFCNT
+
+keystroke_ok:
+ .ifdef FUJICHAT
+ cmp #$20
+ bcc show_cursor ; ignore low ASCII
+ .endif
+ cmp #$9B
+ bne check_backs_key
+ jmp return_key_hit
+
+check_backs_key:
+ cmp #$7E
+ bne check_clear_key
+ jmp backs_key_hit
+
+check_clear_key:
+ cmp #$7D
+ bne normal_key_hit
+ jmp clear_key_hit
+
+normal_key_hit:
+ ldx BUFCNT
+ bpl buffer_character
+ .ifdef FUJICHAT
+ jmp show_cursor
+ .else
+ jmp beep
+ .endif
+
+buffer_character:
+ sta line_buffer,x
+ jsr col80_putbyte
+ inc BUFCNT
+ jmp show_cursor
+
+return_key_hit:
+ jsr print_space
+ lda #$9B
+ ldx BUFCNT
+ sta line_buffer,x
+ inc BUFCNT
+ jsr col80_putbyte
+ jmp get_next_byte
+
+clear_key_hit:
+ .ifndef FUJICHAT
+ jsr clear_screen
+ .endif
+ lda #$00
+ sta line_buffer_index
+ sta BUFCNT
+ jmp get_line
+
+backs_key_hit:
+ jsr print_space
+ lda BUFCNT
+ beq backs_key_done
+ dec COLCRS
+ lda COLCRS
+ clc
+ adc #$01
+ cmp LMARGN
+ bne backs_same_line
+ lda right_margin
+ sta COLCRS
+ dec ROWCRS
+
+backs_same_line:
+ dec BUFCNT
+
+backs_key_done:
+ jmp show_cursor
+
+; ----------------------------------------------------------------------------
+; Ring the margin bell. COL80 doesn't implement the ctrl-2 bell (character
+; 253), and instead of using the GTIA keyclick speaker, it uses POKEY to
+; make a beep
+
+ .ifndef FUJICHAT
+beep: ldy #$00
+ ldx #$AF
+
+beep_delay_x:
+ stx AUDF1
+ stx AUDC1
+
+beep_delay_y:
+ dey
+ bne beep_delay_y
+ dex
+ cpx #$9F
+ bne beep_delay_x
+ jmp show_cursor
+ .endif
+
+; ----------------------------------------------------------------------------
+; Print a space character at the current cursor position. Does not
+; update the cursor position.
+print_space:
+ lda #$00
+ sta inverse_mask
+ .ifndef FUJICHAT
+ lda #$20
+ .endif
+ sta TMPCHR
+ jsr setup_font_ptr
+ jsr setup_screen_ptr
+ jsr write_font_data
+ rts
+
+; ----------------------------------------------------------------------------
+; Get a keystroke (blocking). Just calls the OS K: get-one-byte routine
+; (call by pushing address-minus-one then doing an RTS)
+get_keystroke:
+ lda k_dev_get_hi
+ pha
+ lda k_dev_get_lo
+ pha
+ rts
+
+ .ifndef FUJICHAT
+ .include "col80_init.s"
+ .endif
+
+; ----------------------------------------------------------------------------
+; COL80 vector table, in the format required by the OS. Our HATABS entry
+; will point to this table, and the OS will call the routines listed here
+; via the "call by RTS" method (which is why they're address-minus-one).
+
+; See the entry on HATABS in "Mapping the Atari" or the OS manual.
+
+col80_vector_tab:
+ .word col80_open-1
+ .word col80_close-1
+ .word col80_getbyte-1
+ .word col80_putbyte-1
+ .word col80_close-1
+ .word col80_close-1
+ .ifdef FUJICHAT
+ .byte 0, 0, 0 ; heh.
+ .else
+ jmp col80_init
+ .endif
+
+ .ifndef FUJICHAT
+ .include "col80_entry.s"
+ .endif
+
+; ----------------------------------------------------------------------------
+; Various bits of runtime state here. It's unclear to me why the standard
+; OS buffer location couldn't have been used instead (normally the top
+; half of page 5), or why the other stuff couldn't have been stored in
+; zero page, in locations used by the ROM E: handler (thus unused when
+; it's replaced with COL80). line_buffer_index needs to be preserved
+; across calls to col80_getbyte, but lo_nybble_flag and inverse_mask are
+; freshly calculated every time they're used, so they could be almost
+; anywhere.
+
+ .ifdef FUJICHAT
+ .segment "CODE"
+ .endif
+
+lo_nybble_flag:
+ .byte $00
+
+inverse_mask:
+ .byte $00
+
+line_buffer_index:
+ .byte $12
+
+; ----------------------------------------------------------------------------
+; There's absolutely no reason why this data needs to be included in the
+; binary load file: the line buffer's initial contents are meaningless, they
+; will be blown away the first time anything reads from the E: device.
+
+; Notice the author was running his debugger in COL80 when he built the
+; binary (ASCII "S COL80 7A00 7F80" command still in the buffer).
+
+ .ifdef FUJICHAT
+line_buffer = $03FD ; cassette buffer
+ .else
+line_buffer:
+ .byte $53,$20,$43,$4F,$4C,$38,$30,$20
+ .byte $37,$41,$30,$30,$20,$37,$46,$38
+ .byte $30,$9B,$20,$20,$20,$20,$9B,$27
+ .byte $40,$40,$40,$40,$28,$28,$28,$28
+ .byte $40,$40,$40,$40,$40,$40,$40,$40
+ .byte $40,$40,$40,$40,$40,$40,$40,$40
+ .byte $9B,$FD,$FD,$FD,$FD,$9B
+ .endif
+
+END_ADDRESS = *-1
+
+; I've found a variant (modified version?) of this code, that doesn't
+; include the line_buffer in the file (no reason for it to be there),
+; or the $0C segment, and that has another segment, loaded at $6000,
+; with the run address changed to $6000. The code looks like:
+
+; .org $6000
+; jsr dosini_entry_point
+; lda #$50
+; sta RMARGN
+; lda #$00
+; sta COLOR2
+
+; also, the default colors have been changed in init_graphics_8.
+
+; There are at least two binaries floating around that contain
+; extra (garbage) bytes at the end, presumably from being transferred
+; over XMODEM or similar. They are otherwise identical.
+
diff --git a/src/col80_modified/cruft/col80_main.s.orig b/src/col80_modified/cruft/col80_main.s.orig
new file mode 100644
index 0000000..0b56ee3
--- /dev/null
+++ b/src/col80_modified/cruft/col80_main.s.orig
@@ -0,0 +1,895 @@
+; COL80.COM, aka COL80E.COM, aka COL80HND.COM
+; (and probably several other names)
+
+; Original author unknown
+; License unknown
+; Disassembly and comments by Urchlay
+
+; This is a widely-distributed software 80-column driver for the Atari
+; 8-bit computers. It replaces the OS's E: driver, and uses GRAPHICS 8
+; for display, with 4x8 pixel character cells.
+
+; Disassembly was done with da65, with many iterations of "edit the
+; .info file, disassemble again", and the results were tweaked by hand
+; into something assemblable by dasm (and fairly compatible with other
+; assemblers).
+
+
+; START_ADDRESS is defined in col80_startaddr.s
+ .org START_ADDRESS
+
+; ----------------------------------------------------------------------------
+; Zero page labels (OS equates)
+
+DOSINI = $000C
+ICAX1Z = $002A
+ICAX2Z = $002B
+TMPCHR = $0050
+LMARGN = $0052
+ROWCRS = $0054
+COLCRS = $0055
+DINDEX = $0057
+SAVMSC = $0058
+BUFCNT = $006B
+
+; ----------------------------------------------------------------------------
+; Zero page labels (COL80 equates)
+
+screen_ptr_lo = $00CB
+screen_ptr_hi = $00CC
+font_ptr_lo = $00CD
+font_ptr_hi = $00CE
+
+; ----------------------------------------------------------------------------
+; Non-zeropage RAM labels (OS equates)
+
+COLOR1 = $02C5
+COLOR2 = $02C6
+RUNAD = $02E0
+MEMTOP = $02E5
+SSFLAG = $02FF
+HATABS = $031A
+ICCOM = $0342
+ICBAL = $0344
+ICBAH = $0345
+
+; ----------------------------------------------------------------------------
+; Hardware (memory-mapped I/O, OS equates)
+
+CONSOL = $D01F
+AUDF1 = $D200
+AUDC1 = $D201
+
+; ----------------------------------------------------------------------------
+; OS ROM labels
+
+s_dev_open_lo = $E410 ; (not named in OS sources)
+s_dev_open_hi = $E411 ; ""
+k_dev_get_lo = $E424 ; ""
+k_dev_get_hi = $E425 ; ""
+CIOV = $E456 ; Central Input/Output entry point
+
+; ----------------------------------------------------------------------------
+; Start of COL80. The font is stored in packed form. Each group of 8 bytes
+; defines two glyphs: the upper 4 bits of the 8 bytes, taken together,
+; define the bitmap for the first glyph, and the lower 4 bits are the second.
+; Note that the bits that make up a single character are spread across 8
+; bytes, so it's hard to visualize these even if you're used to reading hex
+; dumps.
+
+; The first 2 characters look like:
+
+; .... .O.. ; $04
+; .... .O.. ; $04
+; O.O. .O.. ; $A4
+; OOO. .O.. ; $E4
+; OOO. .OOO ; $E7
+; .O.. .O.. ; $44
+; .... .O.. ; $04
+; .... .O.. ; $04
+
+; These are the ATASCII heart symbol (character code 0) and the ATASCII
+; control-A line-drawing symbol (code 1).
+
+; Note: unlike the ROM font, this font is stored in ATASCII order instead
+; of the standard Atari character order imposed by the hardware. Like
+; the ROM font, inverse characters are not stored here (the bitmaps get
+; inverted by the driver)
+
+font_data:
+ ; Low ATASCII graphics symbols (code 0-31)
+ .byte $04,$04,$A4,$E4,$E7,$44,$04,$04 ; 7A00
+ .byte $14,$14,$14,$14,$1C,$10,$10,$10 ; 7A08
+ .byte $40,$40,$40,$40,$CC,$44,$44,$44 ; 7A10
+ .byte $18,$18,$24,$24,$42,$42,$81,$81 ; 7A18
+ .byte $10,$10,$30,$30,$73,$73,$F3,$F3 ; 7A20
+ .byte $83,$83,$C3,$C3,$E0,$E0,$F0,$F0 ; 7A28
+ .byte $CF,$CF,$C0,$C0,$00,$00,$00,$00 ; 7A30
+ .byte $00,$00,$00,$00,$0C,$0C,$FC,$FC ; 7A38
+ .byte $00,$00,$00,$40,$A7,$44,$E4,$04 ; 7A40
+ .byte $04,$04,$04,$04,$FF,$04,$04,$04 ; 7A48
+ .byte $00,$00,$60,$F0,$FF,$6F,$0F,$0F ; 7A50
+ .byte $80,$80,$80,$80,$8F,$84,$84,$84 ; 7A58
+ .byte $4C,$4C,$4C,$4C,$FC,$0C,$0C,$0C ; 7A60
+ .byte $40,$4C,$48,$4C,$78,$0C,$06,$00 ; 7A68
+ .byte $00,$44,$E4,$44,$4E,$44,$00,$00 ; 7A70
+ .byte $00,$24,$42,$FF,$42,$24,$00,$00 ; 7A78
+
+ ; Space ! " # etc (codes 32-63)
+ .byte $00,$04,$04,$04,$04,$00,$04,$00 ; 7A80
+ .byte $00,$A0,$AA,$AE,$0A,$0E,$0A,$00 ; 7A88
+ .byte $00,$40,$68,$82,$44,$28,$C2,$40 ; 7A90
+ .byte $00,$C4,$64,$E4,$60,$C0,$40,$00 ; 7A98
+ .byte $00,$44,$82,$82,$82,$82,$82,$44 ; 7AA0
+ .byte $00,$04,$A4,$4E,$E4,$44,$A0,$00 ; 7AA8
+ .byte $00,$00,$00,$0E,$00,$40,$40,$80 ; 7AB0
+ .byte $00,$02,$02,$04,$04,$08,$48,$00 ; 7AB8
+ .byte $00,$E4,$AC,$A4,$A4,$A4,$EE,$00 ; 7AC0
+ .byte $00,$EE,$22,$22,$EE,$82,$EE,$00 ; 7AC8
+ .byte $00,$AE,$A8,$AE,$E2,$22,$2E,$00 ; 7AD0
+ .byte $00,$EE,$82,$E2,$A4,$A4,$E4,$00 ; 7AD8
+ .byte $00,$EE,$AA,$EA,$AE,$A2,$EE,$00 ; 7AE0
+ .byte $00,$00,$00,$44,$00,$44,$04,$08 ; 7AE8
+ .byte $00,$20,$4E,$80,$4E,$20,$00,$00 ; 7AF0
+ .byte $00,$8C,$42,$22,$44,$80,$04,$00 ; 7AF8
+
+ ; @ A B C etc (codes 64-95)
+ .byte $00,$6E,$9A,$BA,$BE,$8A,$6A,$00 ; 7B00
+ .byte $00,$C6,$A8,$C8,$A8,$A8,$C6,$00 ; 7B08
+ .byte $00,$CE,$A8,$AC,$A8,$A8,$CE,$00 ; 7B10
+ .byte $00,$E6,$88,$C8,$8A,$8A,$86,$00 ; 7B18
+ .byte $00,$AE,$A4,$E4,$A4,$A4,$AE,$00 ; 7B20
+ .byte $00,$2A,$2A,$2C,$2A,$2A,$CA,$00 ; 7B28
+ .byte $00,$8A,$8E,$8E,$8A,$8A,$EA,$00 ; 7B30
+ .byte $00,$C4,$AA,$AA,$AA,$AA,$A4,$00 ; 7B38
+ .byte $00,$EE,$AA,$EA,$8A,$8A,$8E,$03 ; 7B40
+ .byte $00,$C6,$A8,$AC,$C2,$A2,$AC,$00 ; 7B48
+ .byte $00,$EA,$4A,$4A,$4A,$4A,$4E,$00 ; 7B50
+ .byte $00,$AA,$AA,$AA,$AE,$AE,$4A,$00 ; 7B58
+ .byte $00,$AA,$4A,$4E,$44,$44,$A4,$00 ; 7B60
+ .byte $00,$EE,$28,$48,$88,$88,$E8,$0E ; 7B68
+ .byte $00,$8E,$82,$42,$42,$22,$22,$0E ; 7B70
+ .byte $00,$00,$40,$A0,$00,$00,$00,$0F ; 7B78
+
+ ; diamond, lowercase letters, control codes (codes 96-127)
+ .byte $00,$00,$00,$46,$E2,$4E,$0E,$00 ; 7B80
+ .byte $00,$80,$80,$C6,$A8,$A8,$C6,$00 ; 7B88
+ .byte $00,$20,$20,$6E,$AE,$A8,$6E,$00 ; 7B90
+ .byte $00,$00,$C0,$86,$CA,$8E,$82,$0C ; 7B98
+ .byte $00,$80,$84,$80,$C4,$A4,$A4,$00 ; 7BA0
+ .byte $00,$08,$28,$0A,$2C,$2A,$2A,$C0 ; 7BA8
+ .byte $00,$40,$40,$4A,$4E,$4A,$4A,$00 ; 7BB0
+ .byte $00,$00,$00,$CE,$AA,$AA,$AE,$00 ; 7BB8
+ .byte $00,$00,$00,$C6,$AA,$C6,$82,$82 ; 7BC0
+ .byte $00,$00,$00,$6E,$88,$86,$8E,$00 ; 7BC8
+ .byte $00,$00,$40,$EA,$4A,$4A,$6E,$00 ; 7BD0
+ .byte $00,$00,$00,$AA,$AA,$AE,$4A,$00 ; 7BD8
+ .byte $00,$00,$00,$AA,$4A,$A6,$A2,$0C ; 7BE0
+ .byte $00,$00,$04,$EE,$4E,$84,$EE,$00 ; 7BE8
+ .byte $40,$4E,$4C,$4E,$4A,$42,$42,$40 ; 7BF0
+ .byte $00,$28,$6C,$EE,$6C,$28,$00,$00 ; 7BF8
+
+right_margin:
+ ; Default value is 79 decimal. Unsure why the author didn't use RMARGN at $53
+ .byte $4F ; 7C00 4F
+
+; ----------------------------------------------------------------------------
+; Start of COL80 code.
+
+; Callback for CIO OPEN command.
+
+col80_open:
+ jsr init_graphics_8 ; 7C01 20 14 7C
+ lda #$00 ; 7C04 A9 00
+ sta ROWCRS ; 7C06 85 54
+ sta COLCRS ; 7C08 85 55
+ nop ; 7C0A EA
+ nop ; 7C0B EA
+ sta BUFCNT ; 7C0C 85 6B
+ lda #$4F ; 7C0E A9 4F
+ sta right_margin ; 7C10 8D 00 7C
+ rts ; 7C13 60
+
+; ----------------------------------------------------------------------------
+; Assembly version of GRAPHICS 8+16 command.
+
+init_graphics_8:
+ lda #$08 ; 7C14 A9 08
+ sta ICAX2Z ; 7C16 85 2B
+ lda #$0C ; 7C18 A9 0C
+ sta ICAX1Z ; 7C1A 85 2A
+ jsr open_s_dev ; 7C1C 20 37 7C
+
+ ; Set COL80's default colors
+ lda #$08 ; 7C1F A9 08
+ sta COLOR2 ; 7C21 8D C6 02
+ nop ; 7C24 EA
+ nop ; 7C25 EA
+ nop ; 7C26 EA
+ lda #$00 ; 7C27 A9 00
+ sta COLOR1 ; 7C29 8D C5 02
+
+ ; Protect ourselves from BASIC and the OS
+ lda #<START_ADDRESS ; 7C2C A9 00
+ sta MEMTOP ; 7C2E 8D E5 02
+ lda #>START_ADDRESS ; 7C31 A9 7A
+ sta MEMTOP+1 ; 7C33 8D E6 02
+ rts ; 7C36 60
+
+; ----------------------------------------------------------------------------
+; Call the OPEN vector for the S: device, using the ROM vector table
+; at $E410. The table stores address-minus-one of each routine, which is
+; meant to actually be called via the RTS instruction (standard 6502
+; technique, but confusing the first time you encounter it)
+
+open_s_dev:
+ lda s_dev_open_hi ; 7C37 AD 11 E4
+ pha ; 7C3A 48
+ lda s_dev_open_lo ; 7C3B AD 10 E4
+ pha ; 7C3E 48
+ rts ; 7C3F 60
+
+; ----------------------------------------------------------------------------
+; Callback for CIO CLOSE command. Note that the routine does nothing, really
+; (the OS will mark the E: device as being closed, but COL80 doesn't do any
+; cleanup).
+; The SPECIAL and GET STATUS callbacks in col80_vector_tab also point here.
+
+col80_close:
+ jmp return_success
+
+; ----------------------------------------------------------------------------
+; Callback for the internal put-one-byte, used by the OS to implement the
+; CIO PUT RECORD and PUT BYTES commands. This routine's one argument is
+; the byte in the accumulator (the character to print).
+
+; First, the routine checks for the cursor control characters it supports.
+; COL80 only handles the EOL and clear-screen codes; trying to print
+; backspaces, arrows, deletes, inserts, etc just causes their ATASCII
+; graphics character to print instead.
+
+col80_putbyte:
+ ; EOL (decimal 155)?
+ cmp #$9B ; 7C43 C9 9B
+ bne check_clear ; 7C45 D0 08
+ lda right_margin ; 7C47 AD 00 7C
+ sta COLCRS ; 7C4A 85 55
+ jmp skip_write ; 7C4C 4C 7C 7C
+
+check_clear:
+ ; Clear (decimal 125)?
+ cmp #$7D ; 7C4F C9 7D
+ bne regular_char ; 7C51 D0 03
+ jmp clear_screen ; 7C53 4C 0B 7D
+
+ ; See if this is an inverse video char (code >= 128)
+regular_char:
+ tax ; 7C56 AA
+ bpl not_inverse ; 7C57 10 07
+ lda #$FF ; 7C59 A9 FF
+ sta inverse_mask ; 7C5B 8D 49 7F
+ bne skip_ninv ; 7C5E D0 05
+
+not_inverse:
+ lda #$00 ; 7C60 A9 00
+ sta inverse_mask ; 7C62 8D 49 7F
+
+skip_ninv:
+ txa ; 7C65 8A
+ and #$7F ; 7C66 29 7F
+ sta TMPCHR ; 7C68 85 50
+ lda DINDEX ; 7C6A A5 57
+ cmp #$08 ; 7C6C C9 08
+ beq graphics_ok ; 7C6E F0 03
+ ; If we're not in GRAPHICS 8 mode, reinitialize ourselves
+ jsr col80_open ; 7C70 20 01 7C
+
+graphics_ok:
+ ; Call the routines that actually print the character
+ jsr setup_font_ptr ; 7C73 20 C9 7C
+ jsr setup_screen_ptr ; 7C76 20 34 7D
+ jsr write_font_data ; 7C79 20 82 7D
+
+skip_write:
+ ; Move the cursor 1 space to the right. This will
+ ; advance us to the next line if we're at the margin,
+ ; and scroll the screen if needed
+ jsr advance_cursor ; 7C7C 20 EE 7C
+
+check_ssflag:
+ ; The OS keyboard interrupt handler will toggle SSFLAG (start/stop fla
+ ; any time the user presses ctrl-1
+ lda SSFLAG ; 7C7F AD FF 02
+ bne check_ssflag ; 7C82 D0 FB
+ jmp return_success ; 7C84 4C 31 7D
+
+; ----------------------------------------------------------------------------
+; Scroll the screen up one line (8 scanlines). This has to move almost 8K of
+; data, so it's noticeably slower than scrolling the GR.0 text screen.
+
+scroll_screen:
+ lda SAVMSC ; 7C87 A5 58
+ sta screen_ptr_lo ; 7C89 85 CB
+ clc ; 7C8B 18
+ adc #$40 ; 7C8C 69 40
+ ; font_ptr_lo is actually being used here as a second pointer into
+ ; screen RAM, instead of its usual use as a pointer into the
+ ; font_data table
+ sta font_ptr_lo ; 7C8E 85 CD
+ lda SAVMSC+1 ; 7C90 A5 59
+ sta screen_ptr_hi ; 7C92 85 CC
+ adc #$01 ; 7C94 69 01
+ sta font_ptr_hi ; 7C96 85 CE
+ ldx #$1D ; 7C98 A2 1D
+ ldy #$00 ; 7C9A A0 00
+
+scroll_line_loop:
+ lda (font_ptr_lo),y ; 7C9C B1 CD
+ sta (screen_ptr_lo),y ; 7C9E 91 CB
+ dey ; 7CA0 88
+ bne scroll_line_loop ; 7CA1 D0 F9
+ inc font_ptr_hi ; 7CA3 E6 CE
+ inc screen_ptr_hi ; 7CA5 E6 CC
+ dex ; 7CA7 CA
+ bne scroll_line_loop ; 7CA8 D0 F2
+
+blank_bottom_row:
+ lda SAVMSC ; 7CAA A5 58
+ clc ; 7CAC 18
+ adc #$C0 ; 7CAD 69 C0
+ sta screen_ptr_lo ; 7CAF 85 CB
+ lda SAVMSC+1 ; 7CB1 A5 59
+ adc #$1C ; 7CB3 69 1C
+ sta screen_ptr_hi ; 7CB5 85 CC
+ lda #$00 ; 7CB7 A9 00
+ tay ; 7CB9 A8
+
+blank_loop:
+ sta (screen_ptr_lo),y ; 7CBA 91 CB
+ dey ; 7CBC 88
+ bne blank_loop ; 7CBD D0 FB
+ inc screen_ptr_hi ; 7CBF E6 CC
+ ldy #$40 ; 7CC1 A0 40
+
+blank_tail:
+ sta (screen_ptr_lo),y ; 7CC3 91 CB
+ dey ; 7CC5 88
+ bpl blank_tail ; 7CC6 10 FB
+ rts ; 7CC8 60
+
+; ----------------------------------------------------------------------------
+; Set up font_ptr_lo/hi to point to the font_data bitmap for the character in
+; TMPCHR. Also sets lo_nybble_flag to let the caller know whether the
+; bitmap is in the upper or lower 4 bits of the bytes pointed to.
+
+setup_font_ptr:
+ lda #$00 ; 7CC9 A9 00
+ sta font_ptr_hi ; 7CCB 85 CE
+ sta lo_nybble_flag ; 7CCD 8D 48 7F
+ lda TMPCHR ; 7CD0 A5 50
+ clc ; 7CD2 18
+ ror ; 7CD3 6A
+ bcc font_hi_nybble ; 7CD4 90 05
+ ldx #$FF ; 7CD6 A2 FF
+ stx lo_nybble_flag ; 7CD8 8E 48 7F
+
+font_hi_nybble:
+ clc ; 7CDB 18
+ rol ; 7CDC 2A
+ rol ; 7CDD 2A
+ rol font_ptr_hi ; 7CDE 26 CE
+ rol ; 7CE0 2A
+ rol font_ptr_hi ; 7CE1 26 CE
+ adc #<font_data ; 7CE3 69 00
+ sta font_ptr_lo ; 7CE5 85 CD
+ lda #>font_data ; 7CE7 A9 7A
+ adc font_ptr_hi ; 7CE9 65 CE
+ sta font_ptr_hi ; 7CEB 85 CE
+ rts ; 7CED 60
+
+; ----------------------------------------------------------------------------
+; Move the cursor one space to the right (to the next line if at the margin,
+; and scroll screen if on the last row)
+
+advance_cursor:
+ inc COLCRS ; 7CEE E6 55
+ lda right_margin ; 7CF0 AD 00 7C
+ cmp COLCRS ; 7CF3 C5 55
+ bcs same_line ; 7CF5 B0 13
+ lda LMARGN ; 7CF7 A5 52
+ sta COLCRS ; 7CF9 85 55
+ lda ROWCRS ; 7CFB A5 54
+ ; $17 is 25 decimal, one row below the lowest on the screen
+ cmp #$17 ; 7CFD C9 17
+ bcc no_scroll ; 7CFF 90 07
+ jsr scroll_screen ; 7D01 20 87 7C
+ ; Move to row 24 after scrolling
+ lda #$16 ; 7D04 A9 16
+ sta ROWCRS ; 7D06 85 54
+
+no_scroll:
+ inc ROWCRS ; 7D08 E6 54
+
+same_line:
+ rts ; 7D0A 60
+
+; ----------------------------------------------------------------------------
+; Clear the screen by setting all screen RAM bytes to zero. Slow, but not
+; as slow as scrolling.
+
+clear_screen:
+ lda SAVMSC ; 7D0B A5 58
+ sta screen_ptr_lo ; 7D0D 85 CB
+ lda SAVMSC+1 ; 7D0F A5 59
+ sta screen_ptr_hi ; 7D11 85 CC
+ ldy #$00 ; 7D13 A0 00
+ ldx #$1D ; 7D15 A2 1D
+ lda #$00 ; 7D17 A9 00
+
+cls_loop:
+ sta (screen_ptr_lo),y ; 7D19 91 CB
+ dey ; 7D1B 88
+ bne cls_loop ; 7D1C D0 FB
+ inc screen_ptr_hi ; 7D1E E6 CC
+ dex ; 7D20 CA
+ bne cls_loop ; 7D21 D0 F6
+ jsr blank_bottom_row ; 7D23 20 AA 7C
+ lda LMARGN ; 7D26 A5 52
+ sta COLCRS ; 7D28 85 55
+ lda #$00 ; 7D2A A9 00
+ sta ROWCRS ; 7D2C 85 54
+ ; redundant JMP
+ jmp return_success ; 7D2E 4C 31 7D
+
+; ----------------------------------------------------------------------------
+; CIO expects the Y register to contain a status code.
+; 1 means success (no error). Lots of COL80's routines
+; jump here.
+
+return_success:
+ ldy #$01 ; 7D31 A0 01
+ rts ; 7D33 60
+
+; ----------------------------------------------------------------------------
+; Set screen_ptr_lo/hi to point to the address of the first byte of graphics
+; data at the current cursor position.
+
+setup_screen_ptr:
+ ldy ROWCRS ; 7D34 A4 54
+ lda SAVMSC ; 7D36 A5 58
+ clc ; 7D38 18
+ adc row_low_offset_tab,y ; 7D39 79 52 7D
+ sta screen_ptr_lo ; 7D3C 85 CB
+ lda SAVMSC+1 ; 7D3E A5 59
+ adc row_high_offset_tab,y ; 7D40 79 6A 7D
+ sta screen_ptr_hi ; 7D43 85 CC
+ lda COLCRS ; 7D45 A5 55
+ lsr ; 7D47 4A
+ clc ; 7D48 18
+ adc screen_ptr_lo ; 7D49 65 CB
+ bcc hi_byte_ok ; 7D4B 90 02
+ inc screen_ptr_hi ; 7D4D E6 CC
+
+hi_byte_ok:
+ sta screen_ptr_lo ; 7D4F 85 CB
+ rts ; 7D51 60
+
+; ----------------------------------------------------------------------------
+; Tables of offsets for setup_screen_ptr, to avoid doing multiplication at
+; runtime (the 6502 lacks a MUL instruction, so it's slow...)
+
+row_low_offset_tab:
+ .byte $00,$40,$80,$C0,$00,$40,$80,$C0 ; 7D52
+ .byte $00,$40,$80,$C0,$00,$40,$80,$C0 ; 7D5A
+ .byte $00,$40,$80,$C0,$00,$40,$80,$C0 ; 7D62
+
+row_high_offset_tab:
+ .byte $00,$01,$02,$03,$05,$06,$07,$08 ; 7D6A
+ .byte $0A,$0B,$0C,$0D,$0F,$10,$11,$12 ; 7D72
+ .byte $14,$15,$16,$17,$19,$1A,$1B,$1C ; 7D7A
+
+; ----------------------------------------------------------------------------
+; Copy pixel data from the font table to screen RAM.
+; font_ptr_lo/hi must point to the correct character, and screen_ptr_lo/hi
+; must point to the correct screen address for the current cursor position.
+; This routine has separate execution paths for even- and odd-numbered
+; cursor positions, since each byte of screen RAM holds data for two
+; adjacent characters (and when printing to one of them, the other needs
+; to be left undisturbed!)
+
+write_font_data:
+ lda COLCRS ; 7D82 A5 55
+ clc ; 7D84 18
+ ror ; 7D85 6A
+ bcc write_font_data_even ; 7D86 90 31
+ ldx #$00 ; 7D88 A2 00
+ ldy #$00 ; 7D8A A0 00
+
+get_font_nybble_odd:
+ lda (font_ptr_lo),y ; 7D8C B1 CD
+ bit lo_nybble_flag ; 7D8E 2C 48 7F
+ bne lo_nybble_odd ; 7D91 D0 04
+ ; glyph we want is stored in top 4 bits of font byte,
+ ; shift it down to the bottom 4 bits
+ lsr ; 7D93 4A
+ lsr ; 7D94 4A
+ lsr ; 7D95 4A
+ lsr ; 7D96 4A
+
+lo_nybble_odd:
+ eor inverse_mask ; 7D97 4D 49 7F
+ and #$0F ; 7D9A 29 0F
+ sta TMPCHR ; 7D9C 85 50
+ ldy scanline_offset_tab,x ; 7D9E BC EA 7D
+ lda (screen_ptr_lo),y ; 7DA1 B1 CB
+ and #$F0 ; 7DA3 29 F0
+ ora TMPCHR ; 7DA5 05 50
+ sta (screen_ptr_lo),y ; 7DA7 91 CB
+ inx ; 7DA9 E8
+ cpx #$07 ; 7DAA E0 07
+ bne screen_ptr_ok_odd ; 7DAC D0 02
+ inc screen_ptr_hi ; 7DAE E6 CC
+
+screen_ptr_ok_odd:
+ cpx #$08 ; 7DB0 E0 08
+ beq write_font_done_odd ; 7DB2 F0 04
+ txa ; 7DB4 8A
+ tay ; 7DB5 A8
+ bne get_font_nybble_odd ; 7DB6 D0 D4
+
+write_font_done_odd:
+ rts ; 7DB8 60
+
+; ----------------------------------------------------------------------------
+; Write data to even-numbered columns, very similar to the above
+
+write_font_data_even:
+ ldx #$00 ; 7DB9 A2 00
+ ldy #$00 ; 7DBB A0 00
+
+get_font_nybble_even:
+ lda (font_ptr_lo),y ; 7DBD B1 CD
+ bit lo_nybble_flag ; 7DBF 2C 48 7F
+ beq hi_nybble_even ; 7DC2 F0 04
+ asl ; 7DC4 0A
+ asl ; 7DC5 0A
+ asl ; 7DC6 0A
+ asl ; 7DC7 0A
+
+hi_nybble_even:
+ eor inverse_mask ; 7DC8 4D 49 7F
+ and #$F0 ; 7DCB 29 F0
+ sta TMPCHR ; 7DCD 85 50
+ ldy scanline_offset_tab,x ; 7DCF BC EA 7D
+ lda (screen_ptr_lo),y ; 7DD2 B1 CB
+ and #$0F ; 7DD4 29 0F
+ ora TMPCHR ; 7DD6 05 50
+ sta (screen_ptr_lo),y ; 7DD8 91 CB
+ inx ; 7DDA E8
+ cpx #$07 ; 7DDB E0 07
+ bne screen_ptr_ok_even ; 7DDD D0 02
+ inc screen_ptr_hi ; 7DDF E6 CC
+
+screen_ptr_ok_even:
+ cpx #$08 ; 7DE1 E0 08
+ beq write_font_done_even ; 7DE3 F0 04
+ txa ; 7DE5 8A
+ tay ; 7DE6 A8
+ bne get_font_nybble_even ; 7DE7 D0 D4
+
+write_font_done_even:
+ rts ; 7DE9 60
+
+; ----------------------------------------------------------------------------
+
+scanline_offset_tab:
+ .byte $00,$28,$50,$78,$A0,$C8,$F0,$18 ; 7DEA
+
+; ----------------------------------------------------------------------------
+; Callback for the internal get-one-byte, used by the OS to implement the
+; CIO GET RECORD and GET BYTES commands. This routine takes no arguments,
+; and returns the read byte in the accumulator.
+
+; Internally, COL80 maintains a line buffer. Each time col80_getbyte is
+; called, it returns the next character in the buffer. If the buffer's
+; empty (or if the last call returned the last character), a new line
+; of input is read from the user (and the first character is returned).
+; This is exactly how the OS E: device works.
+
+col80_getbyte:
+ lda BUFCNT ; 7DF2 A5 6B
+ beq get_line ; 7DF4 F0 0E
+
+get_next_byte:
+ ldx line_buffer_index ; 7DF6 AE 4A 7F
+ lda line_buffer,x ; 7DF9 BD 4B 7F
+ dec BUFCNT ; 7DFC C6 6B
+ inc line_buffer_index ; 7DFE EE 4A 7F
+ jmp return_success ; 7E01 4C 31 7D
+
+; ----------------------------------------------------------------------------
+; Get a line of input from the user, terminated by the Return key.
+
+get_line:
+ lda #$00 ; 7E04 A9 00
+ sta BUFCNT ; 7E06 85 6B
+ sta line_buffer_index ; 7E08 8D 4A 7F
+
+show_cursor:
+ lda #$20 ; 7E0B A9 20
+ sta TMPCHR ; 7E0D 85 50
+ lda #$FF ; 7E0F A9 FF
+ sta inverse_mask ; 7E11 8D 49 7F
+ jsr setup_font_ptr ; 7E14 20 C9 7C
+ jsr setup_screen_ptr ; 7E17 20 34 7D
+ jsr write_font_data ; 7E1A 20 82 7D
+ jsr get_keystroke ; 7E1D 20 B7 7E
+ cpy #$01 ; 7E20 C0 01
+ beq keystroke_ok ; 7E22 F0 07
+ ldy #$00 ; 7E24 A0 00
+ sty line_buffer_index ; 7E26 8C 4A 7F
+ sty BUFCNT ; 7E29 84 6B
+
+keystroke_ok:
+ cmp #$9B ; 7E2B C9 9B
+ bne check_backs_key ; 7E2D D0 03
+ jmp return_key_hit ; 7E2F 4C 52 7E
+
+check_backs_key:
+ cmp #$7E ; 7E32 C9 7E
+ bne check_clear_key ; 7E34 D0 03
+ jmp backs_key_hit ; 7E36 4C 71 7E
+
+check_clear_key:
+ cmp #$7D ; 7E39 C9 7D
+ bne normal_key_hit ; 7E3B D0 03
+ jmp clear_key_hit ; 7E3D 4C 64 7E
+
+normal_key_hit:
+ ldx BUFCNT ; 7E40 A6 6B
+ bpl buffer_character ; 7E42 10 03
+ jmp beep ; 7E44 4C 8F 7E
+
+buffer_character:
+ sta line_buffer,x ; 7E47 9D 4B 7F
+ jsr col80_putbyte ; 7E4A 20 43 7C
+ inc BUFCNT ; 7E4D E6 6B
+ jmp show_cursor ; 7E4F 4C 0B 7E
+
+return_key_hit:
+ jsr print_space ; 7E52 20 A4 7E
+ lda #$9B ; 7E55 A9 9B
+ ldx BUFCNT ; 7E57 A6 6B
+ sta line_buffer,x ; 7E59 9D 4B 7F
+ inc BUFCNT ; 7E5C E6 6B
+ jsr col80_putbyte ; 7E5E 20 43 7C
+ jmp get_next_byte ; 7E61 4C F6 7D
+
+clear_key_hit:
+ jsr clear_screen ; 7E64 20 0B 7D
+ lda #$00 ; 7E67 A9 00
+ sta line_buffer_index ; 7E69 8D 4A 7F
+ sta BUFCNT ; 7E6C 85 6B
+ jmp get_line ; 7E6E 4C 04 7E
+
+backs_key_hit:
+ jsr print_space ; 7E71 20 A4 7E
+ lda BUFCNT ; 7E74 A5 6B
+ beq backs_key_done ; 7E76 F0 14
+ dec COLCRS ; 7E78 C6 55
+ lda COLCRS ; 7E7A A5 55
+ clc ; 7E7C 18
+ adc #$01 ; 7E7D 69 01
+ cmp LMARGN ; 7E7F C5 52
+ bne backs_same_line ; 7E81 D0 07
+ lda right_margin ; 7E83 AD 00 7C
+ sta COLCRS ; 7E86 85 55
+ dec ROWCRS ; 7E88 C6 54
+
+backs_same_line:
+ dec BUFCNT ; 7E8A C6 6B
+
+backs_key_done:
+ jmp show_cursor ; 7E8C 4C 0B 7E
+
+; ----------------------------------------------------------------------------
+; Ring the margin bell. COL80 doesn't implement the ctrl-2 bell (character
+; 253), and instead of using the GTIA keyclick speaker, it uses POKEY to
+; make a beep
+
+beep: ldy #$00 ; 7E8F A0 00
+ ldx #$AF ; 7E91 A2 AF
+
+beep_delay_x:
+ stx AUDF1 ; 7E93 8E 00 D2
+ stx AUDC1 ; 7E96 8E 01 D2
+
+beep_delay_y:
+ dey ; 7E99 88
+ bne beep_delay_y ; 7E9A D0 FD
+ dex ; 7E9C CA
+ cpx #$9F ; 7E9D E0 9F
+ bne beep_delay_x ; 7E9F D0 F2
+ jmp show_cursor ; 7EA1 4C 0B 7E
+
+; ----------------------------------------------------------------------------
+; Print a space character at the current cursor position. Does not
+; update the cursor position.
+print_space:
+ lda #$00 ; 7EA4 A9 00
+ sta inverse_mask ; 7EA6 8D 49 7F
+ lda #$20 ; 7EA9 A9 20
+ sta TMPCHR ; 7EAB 85 50
+ jsr setup_font_ptr ; 7EAD 20 C9 7C
+ jsr setup_screen_ptr ; 7EB0 20 34 7D
+ jsr write_font_data ; 7EB3 20 82 7D
+ rts ; 7EB6 60
+
+; ----------------------------------------------------------------------------
+; Get a keystroke (blocking). Just calls the OS K: get-one-byte routine
+; (call by pushing address-minus-one then doing an RTS)
+get_keystroke:
+ lda k_dev_get_hi ; 7EB7 AD 25 E4
+ pha ; 7EBA 48
+ lda k_dev_get_lo ; 7EBB AD 24 E4
+ pha ; 7EBE 48
+ rts ; 7EBF 60
+
+; ----------------------------------------------------------------------------
+; Initialization callback. The OS will call this on coldstart (or would do,
+; if the driver were in ROM), and also on warmstart (because we stole the
+; DOSINI vector).
+; This routine is also the first thing that gets called by the mainline
+; init code. Its job is to install COL80 in the handler table at HATABS.
+; Actually the handler is first installed as X:, then the main init code
+; fixes this up to E: unless the user is holding down SELECT. This allows
+; the user to toggle between the 40-column ROM E: and COL80 without doing
+; a full reboot. No idea if this was a documented feature or something the
+; author used for development/debugging.
+
+col80_init:
+ ldy #$00 ; 7EC0 A0 00
+
+next_hatab_slot:
+ lda HATABS,y ; 7EC2 B9 1A 03
+ beq register_x_handler ; 7EC5 F0 0A
+ iny ; 7EC7 C8
+ iny ; 7EC8 C8
+ iny ; 7EC9 C8
+ cpy #$20 ; 7ECA C0 20
+ bcc next_hatab_slot ; 7ECC 90 F4
+ jmp return_success ; 7ECE 4C 31 7D
+
+register_x_handler:
+ lda #$58 ; 7ED1 A9 58
+ sta HATABS,y ; 7ED3 99 1A 03
+ lda #<col80_vector_tab ; 7ED6 A9 E5
+ iny ; 7ED8 C8
+ sta HATABS,y ; 7ED9 99 1A 03
+ lda #>col80_vector_tab ; 7EDC A9 7E
+ iny ; 7EDE C8
+ sta HATABS,y ; 7EDF 99 1A 03
+ jmp return_success ; 7EE2 4C 31 7D
+
+; ----------------------------------------------------------------------------
+; COL80 vector table, in the format required by the OS. Our HATABS entry
+; will point to this table, and the OS will call the routines listed here
+; via the "call by RTS" method (which is why they're address-minus-one).
+
+; See the entry on HATABS in "Mapping the Atari" or the OS manual.
+
+col80_vector_tab:
+ .word col80_open-1 ; 7EE5 00 7C
+ .word col80_close-1 ; 7EE7 3F 7C
+ .word col80_getbyte-1 ; 7EE9 F1 7D
+ .word col80_putbyte-1 ; 7EEB 42 7C
+ .word col80_close-1 ; 7EED 3F 7C
+ .word col80_close-1 ; 7EEF 3F 7C
+ jmp col80_init ; 7EF1 4C C0 7E
+
+; ----------------------------------------------------------------------------
+; The OS jumps here on warmstart (also, this is the run address in our
+; binary load file)
+
+dosini_entry_point:
+ nop ; 7EF4 EA
+ nop ; 7EF5 EA
+ nop ; 7EF6 EA
+
+main_entry_point:
+ jsr col80_init ; 7EF7 20 C0 7E
+ lda CONSOL ; 7EFA AD 1F D0
+ and #$04 ; 7EFD 29 04
+ beq no_e_handler ; 7EFF F0 2F
+ lda #$0C ; 7F01 A9 0C
+ sta ICCOM ; 7F03 8D 42 03
+ ldx #$00 ; 7F06 A2 00
+ jsr CIOV ; 7F08 20 56 E4
+ lda #$58 ; 7F0B A9 58
+ sta font_ptr_lo ; 7F0D 85 CD
+ lda #$03 ; 7F0F A9 03
+ sta ICCOM ; 7F11 8D 42 03
+ lda #$CD ; 7F14 A9 CD
+ sta ICBAL ; 7F16 8D 44 03
+ lda #$00 ; 7F19 A9 00
+ sta ICBAH ; 7F1B 8D 45 03
+ ldx #$00 ; 7F1E A2 00
+ jsr CIOV ; 7F20 20 56 E4
+ ldy #$07 ; 7F23 A0 07
+ lda #<col80_vector_tab ; 7F25 A9 E5
+ sta HATABS,y ; 7F27 99 1A 03
+ lda #>col80_vector_tab ; 7F2A A9 7E
+ iny ; 7F2C C8
+ sta HATABS,y ; 7F2D 99 1A 03
+no_e_handler:
+ lda #<START_ADDRESS ; 7F30 A9 00
+ sta MEMTOP ; 7F32 8D E5 02
+ lda #>START_ADDRESS ; 7F35 A9 7A
+ sta MEMTOP+1 ; 7F37 8D E6 02
+ jmp return_success ; 7F3A 4C 31 7D
+
+; ----------------------------------------------------------------------------
+; (when does this actually get called? da65 can't find any references
+; to it, and it's not a run or init address in the binary load file)
+ lda #<dosini_entry_point ; 7F3D A9 F4
+ sta DOSINI ; 7F3F 85 0C
+ lda #>dosini_entry_point ; 7F41 A9 7E
+ sta DOSINI+1 ; 7F43 85 0D
+ jmp main_entry_point ; 7F45 4C F7 7E
+
+; ----------------------------------------------------------------------------
+; Various bits of runtime state here. It's unclear to me why the standard
+; OS buffer location couldn't have been used instead (normally the top
+; half of page 5), or why the other stuff couldn't have been stored in
+; zero page, in locations used by the ROM E: handler (thus unused when
+; it's replaced with COL80). line_buffer_index needs to be preserved
+; across calls to col80_getbyte, but lo_nybble_flag and inverse_mask are
+; freshly calculated every time they're used, so they could be almost
+; anywhere.
+
+lo_nybble_flag:
+ .byte $00 ; 7F48 00
+
+inverse_mask:
+ .byte $00 ; 7F49 00
+
+line_buffer_index:
+ .byte $12 ; 7F4A 12
+
+; ----------------------------------------------------------------------------
+; There's absolutely no reason why this data needs to be included in the
+; binary load file: the line buffer's initial contents are meaningless, they
+; will be blown away the first time anything reads from the E: device.
+
+; Notice the author was running his debugger in COL80 when he built the
+; binary (ASCII "S COL80 7A00 7F80" command still in the buffer).
+
+line_buffer:
+ .byte $53,$20,$43,$4F,$4C,$38,$30,$20 ; 7F4B
+ .byte $37,$41,$30,$30,$20,$37,$46,$38 ; 7F53
+ .byte $30,$9B,$20,$20,$20,$20,$9B,$27 ; 7F5B
+ .byte $40,$40,$40,$40,$28,$28,$28,$28 ; 7F63
+ .byte $40,$40,$40,$40,$40,$40,$40,$40 ; 7F6B
+ .byte $40,$40,$40,$40,$40,$40,$40,$40 ; 7F73
+ .byte $9B,$FD,$FD,$FD,$FD,$9B ; 7F7B
+
+END_ADDRESS = *-1
+
+; I've found a variant (modified version?) of this code, that doesn't
+; include the line_buffer in the file (no reason for it to be there),
+; or the $0C segment, and that has another segment, loaded at $6000,
+; with the run address changed to $6000. The code looks like:
+
+; .org $6000
+; jsr dosini_entry_point
+; lda #$50
+; sta RMARGN
+; lda #$00
+; sta COLOR2
+
+; also, the default colors have been changed in init_graphics_8.
+
+; There are at least two binaries floating around that contain
+; extra (garbage) bytes at the end, presumably from being transferred
+; over XMODEM or similar. They are otherwise identical.
+
diff --git a/src/col80_modified/cruft/col80_main.xex b/src/col80_modified/cruft/col80_main.xex
new file mode 100644
index 0000000..90208c3
--- /dev/null
+++ b/src/col80_modified/cruft/col80_main.xex
Binary files differ
diff --git a/src/col80_modified/cruft/col80_orig.xex b/src/col80_modified/cruft/col80_orig.xex
new file mode 100644
index 0000000..f5f9548
--- /dev/null
+++ b/src/col80_modified/cruft/col80_orig.xex
Binary files differ
diff --git a/src/col80_modified/cruft/col80_runad_seg.s b/src/col80_modified/cruft/col80_runad_seg.s
new file mode 100644
index 0000000..234d621
--- /dev/null
+++ b/src/col80_modified/cruft/col80_runad_seg.s
@@ -0,0 +1,13 @@
+
+; Third segment is the run address
+
+;.ifdef FUJICHAT
+;INITAD = $02E2
+; .word INITAD
+; .word INITAD+1
+; .word dosini_entry_point
+;.else
+ .word RUNAD
+ .word RUNAD+1
+ .word dosini_entry_point
+;.endif
diff --git a/src/col80_modified/cruft/col80_startaddr.s b/src/col80_modified/cruft/col80_startaddr.s
new file mode 100644
index 0000000..d88203b
--- /dev/null
+++ b/src/col80_modified/cruft/col80_startaddr.s
@@ -0,0 +1,7 @@
+
+ .ifdef FUJICHAT
+START_ADDRESS = $9C01 ; subtract $0800 (2048) if using BASIC or other cart
+;START_ADDRESS = $7A00
+ .else
+START_ADDRESS = $7A00
+ .endif
diff --git a/src/col80_modified/cruft/col80_startup.s b/src/col80_modified/cruft/col80_startup.s
new file mode 100644
index 0000000..b170a3c
--- /dev/null
+++ b/src/col80_modified/cruft/col80_startup.s
@@ -0,0 +1,4 @@
+
+ .include "col80_include.s"
+ .include "col80_init.s"
+ .include "col80_entry.s"
diff --git a/src/col80_modified/cruft/dasm2atasm b/src/col80_modified/cruft/dasm2atasm
new file mode 100755
index 0000000..b7ebe66
--- /dev/null
+++ b/src/col80_modified/cruft/dasm2atasm
@@ -0,0 +1,362 @@
+#!/usr/bin/perl -w
+
+=head1 NAME
+
+dasm2atasm - converts 6502 assembly in DASM syntax to ATASM (or MAC/65) format.
+
+=head1 SYNOPSIS
+
+ dasm2atasm mycode.asm
+
+Writes output to I<mycode.m65>
+
+ dasm2atasm stuff.asm other.m65
+
+Reads from I<stuff.asm>, writes to I<other.m65>
+
+=head1 DESCRIPTION
+
+B<dasm2atasm> tries its best to convert DASM's syntax into something
+that B<ATASM> can use. Since B<ATASM>'s syntax is 99% compatible with
+that of B<MAC/65>, B<dasm2atasm> can be used for that as well.
+
+=head1 CAVEATS
+
+There are a few B<DASM> directives that aren't quite supported by
+B<ATASM>.
+
+=over 4
+
+=item echo
+
+In B<DASM> syntax, I<echo> can interpolate values, like so:
+
+ echo $100-*, " bytes of zero page left"
+
+B<ATASM>'s closest equivalent to I<echo> is I<.warn>, but it doesn't
+allow multiple arguments or interpolation. For now, B<dasm2atasm> just
+comments out the line with the I<echo> directive.
+
+=item seg and seg.u
+
+B<ATASM> just plain doesn't support segments. These directives will
+just be commented out. This I<shouldn't> have any effect on the
+object code.
+
+=item sta.w, sty.w, stx.w
+
+B<ATASM> doesn't provide a way to force word addressing, when the operand
+of a store instruction will allow zero page addressing to be used. You'll
+run into this a lot in Atari 2600 code, or any other 6502 code that has to
+maintain sync with an external piece of hardware (using word addressing
+causes the 6502 to use an extra CPU cycle, which is the only way to cause
+a 1-cycle delay).
+
+For now, we're just converting any I<st?.w> instructions to the appropriate
+I<.byte> directives, like so:
+
+ ;;;;; dasm2atasm: was `sta.w COLUPF', using .byte to generate opcode
+ .byte $8d, COLUPF, $00
+
+This works fine if I<COLUPF> is a zero-page label. It's possible, though
+unlikely, that you'll run across code where the programmer has used I<sta.w>
+with a label that would already cause absolute word addressing to be used,
+in which case the extra I<$00> will break our code (literally: I<$00> is
+the I<BRK> instruction!)
+
+This isn't likely to be fixed by I<dasm2atasm>. The correct fix will be to
+support I<sta.w> and friends in B<ATASM> itself, which may happen in the
+future.
+
+=item . (dot)
+
+B<DASM> allows the use of I<.> or I<*> to represent the current program counter
+in expressions. B<ATASM> only allows I<*>, and unless I want to include a
+full expression-parser in B<dasm2atasm>, I can't reliably translate this.
+
+For now, you'll have to fix this yourself. Future versions will at least
+make an attempt, but this one doesn't.
+
+=back
+
+=head1 AUTHOR
+
+B. Watson I<< <urchlay@urchlay.com> >>. Comments & constructive criticism
+welcome, or just a friendly `hello'. Spam will be redirected to /dev/null
+and so will the spammer's entire domain.
+
+=cut
+
+sub usage {
+ print <<EOF;
+Usage: $0 -[aclmr] infile.asm [outfile.m65]
+
+EOF
+ exit 1;
+}
+
+sub get_mac_sub {
+ my $rex = shift;
+ my $code = "sub { s/($rex)/\\U\$1/gio };";
+ #warn "code is $code";
+ return eval "$code";
+}
+
+sub unhex {
+ # makes a proper $xx, $xx, $xx list of bytes
+ # from a list of hex digits, spaces optional.
+ my $bytes = shift;
+ my $ret = "";
+
+ $bytes =~ s/\s//g;
+
+ #warn "unhex: bytes is $bytes";
+
+ for($bytes =~ /(..)/g) {
+ #warn "unhex: found $_";
+ $ret .= "\$$_, ";
+ }
+
+ chop $ret;
+ chop $ret;
+
+ return $ret;
+}
+
+sub fix_include {
+ my $inc = shift;
+ my $old = $inc;
+ $inc =~ s/\.(\w+)("?)$/.m65$2/;
+
+ if($recursive) {
+ system("$cmd $old $inc");
+ } else {
+ warn "Don't forget to convert included file `$old' to .m65 format!\n";
+ }
+ return $inc;
+}
+
+sub do_subs {
+ # Do the dirty work of the substitutions. Only reason we have this
+ # as a subroutine of its own is for profiling purposes (and we do
+ # spend a *lot* of time here!)
+ my $line = shift;
+
+ for($line) {
+ s/^(\@?\w+):/$1/; # no colons after labels, in atasm
+ s/%/~/g; # binary constant
+ s/!=/<>/g; # inequality
+
+ s/^(\s+)\.?echo(.*)/;;;;;$1.warn$2/i &&
+ do { warn "$in, line $.:\n\t`.warn' not fully compatible with dasm's `echo', commented out\n" }
+ && next;
+
+ # This is supposed to change e.g. `bpl .label' to `bpl @label'
+ s/^(\s+)([a-z]{3})(\s+)\.(\w+)/$1$2$3\@$4/i
+ && next;
+
+
+ s/{(\d)}/%$1/g; # macro arg (gotta do this *after* bin. constants!)
+
+# atasm doesn't support shifts, emulate with multiply/divide
+ s/\s*<<\s*(\d+)/"*" . 2**$1/eg;
+ s/\s*>>\s*(\d+)/"\/" . 2**$1/eg;
+
+# atasm chokes sometimes when there's whitespace around an operator
+# unfortunately, a construct like `bne *-1' can't afford to lose the
+# space before the *... why, oh why, does * have to be both multiply and
+# program counter? *sigh*
+
+# s/\s*([-!|\/+*&])\s*/$1/g;
+
+# ARGH. Why does dasm allow `byte #1, #2, #3'... and why do people *use* it?!
+ s/^(\s+)\.?byte(\s+)/$1.byte$2/i && do { s/#//g } && next;
+ s/^(\s+)\.?word(\s+)/$1.word$2/i && do { s/#//g } && next;
+ s/^(\s+)\.?dc\.w(\s+)/$1.word$2/i && do { s/#//g } && next;
+ s/^(\s+)\.?dc(?:\.b)?(\s+)/$1.byte$2/i && do { s/#//g } && next;
+
+# 20070529 bkw: turn ".DS foo" into ".DC foo 0"
+ s/^(\s+)\.?ds(\s+)(\S+)/$1.dc $3 0 /i && do { s/#//g } && next;
+
+# I really want to add `hex' to atasm. 'til then though, fake with .byte
+ s/^(\s+)\.?hex\s+(.*)/$1 . '.byte ' .
+ unhex($2)/ie && next;
+
+ s/^(\s+)\.?subroutine(.*)/$1.local$2/i && next;
+ s/^(\s+)\.?include(\s+)(.*)/$1 . '.include' . $2 . fix_include($3)/gie
+ && next;
+ s/^(\s+)\.?equ\b/$1=/i && next;
+ s/^(\s+)\.?repeat\b/$1.rept/i && next;
+ s/^(\s+)\.?repend\b/$1.endr/i && next;
+ s/^(\s+)\.?endm\b/$1.endm/i && next;
+ s/^(\s+)\.?org(\s+)([^,]*).*$/$1*=$2$3/i && next;
+ s/^(\s+)\.?incbin\b/$1\.incbin/i && next;
+ s/^(\s+)\.?err(.*)/$1.error$2/i && next; # TODO: see if atasm allows `.error' with no message.
+ s/^(\s+)\.?ifconst\s+(.*)/$1.if .def $2/i
+ && next; # TODO: test this!
+ s/^(\s+)\.?else/$1.else/i && next;
+ s/^(\s+)\.?endif/$1.endif/i && next;
+ s/^(\s+)\.?if\s+(.*)/$1.if $2/i && next;
+
+ # stuff that doesn't work:
+ s/^(\s+)(\.?seg(\..)?\s.*)/;;;;; dasm2atasm: `seg' not supported by atasm\n;;;;;$1$2/i
+ && next;
+ s/^(\s+)(\.?processor\s.*)/;;;;; dasm2atasm: `processor' not supported by atasm\n;;;;;$1$2/i
+ && next;
+
+ s/^(\s+)sta\.w(\s+)(.*)/;;;;; dasm2atasm: was `sta.w $3', using .byte to generate opcode\n$1.byte \$8d, <$3, >$3/i
+ && next;
+
+ s/^(\s+)stx\.w(\s+)(.*)/;;;;; dasm2atasm: was `stx.w $3', using .byte to generate opcode\n$1.byte \$8e, <$3, >$3/i
+ && next;
+
+ s/^(\s+)sta\.w(\s+)(.*)/;;;;; dasm2atasm: was `sty.w $3', using .byte to generate opcode\n$1.byte \$8c, <$3, >$3/i
+ && next;
+
+ # atasm lacks `align', so make up for it with a macro
+ if(s/(\s)\.?align(\s+)(.*)/$1ALIGN$2$3/i) {
+ if(!$align_defined) { # only gotta define it if not already defined.
+ for($align_macro) {
+ $_ =~ s/^/($linenum += 10) . " "/gme if $linenum;
+ $_ =~ s/\n/\x9b/g if $a8eol;
+ }
+
+ print OUT $align_macro; # no, I wouldn't use these globals in a CS class assignment.
+ $align_defined++;
+ }
+ next;
+ }
+
+ # macros. This is by far the biggest pain in the ass yet.
+ s/(\s)\.?mac\b/$1.macro/i;
+ if(/(\s)\.macro(\s+)(\w+)/) {
+ $mac_regex .= "|\\b$3\\b";
+ $mac_sub = get_mac_sub($mac_regex);
+ }
+
+ if(ref $mac_sub) { # if we've found at least one macro so far...
+ &$mac_sub; # CAPITALIZE everything matching a macro name
+ } # note: this code assumes macros are *always* defined before they're
+ # used. atasm requires this, but does dasm?
+
+ }
+ return $line;
+}
+
+## main() ##
+
+$ca65 = 0;
+$a8eol = 0;
+$linenum = 0;
+$recursive = 0;
+
+$cmd = $0;
+
+while($ARGV[0] =~ /^-/i) {
+ my $opt = shift;
+ $cmd .= " $opt";
+
+ if($opt eq "-c") {
+ $ca65++;
+ } elsif($opt eq "-a") {
+ $a8eol++;
+ } elsif($opt eq "-l") {
+ $linenum = 1000;
+ } elsif($opt eq "-m") {
+ $a8eol++;
+ $linenum = 1000;
+ } elsif($opt eq "-r") {
+ $recursive++;
+ } elsif($opt eq "--") {
+ last;
+ } else {
+ warn "Unknown option '$opt'\n";
+ usage;
+ }
+}
+
+if($ca65 && ($linenum || $a8eol)) {
+ die "Can't use line numbers and/or Atari EOLs with ca65 output\n";
+}
+
+$align_macro = <<EOF;
+;;;;;; ALIGN macro defined by dasm2atasm
+ .macro ALIGN
+ *= [[*/%1]+1] * %1
+ .endm
+EOF
+
+$align_defined = 0; # we only need to emit the macro definition once.
+
+$in = shift || usage;
+$out = shift;
+
+($out = $in) =~ s/(\.\w+)?$/.m65/ unless $out;
+
+die "$0: can't use $in for both input and output\n" if $out eq $in;
+
+open IN, "<$in" or die "Can't read $in: $!\n";
+open OUT, ">$out" or die "Can't write to $out: $!\n";
+
+$hdr = <<EOF;
+;;; Converted from DASM syntax with command:
+; $cmd $in $out
+
+EOF
+
+for($hdr) {
+ $_ =~ s/^/($linenum += 10) . " "/gme if $linenum;
+ $_ =~ s/\n/\x9b/g if $a8eol;
+}
+
+print OUT $hdr;
+
+if($ca65) {
+ print OUT <<EOF;
+;;; ca65 features enabled by dasm2atasm
+; To build with ca65:
+; ca65 -o foo.o -t none foo.asm
+; ld65 -o foo.bin -t none foo.o
+.FEATURE pc_assignment
+.FEATURE labels_without_colons
+
+EOF
+}
+
+$mac_regex = "!THIS_ISNT_SUPPOSED_TO_MATCH";
+$mac_sub = ""; # this will be the code ref we call to match $mac_regex
+
+while(<IN>) {
+ chomp;
+ s/\r//; # you might not want this on dos/win, not sure if it matters.
+ $label = "";
+
+ if(/^(\w+)\s*=\s*\1/i) {
+ print OUT ";;;;; dasm2atasm: labels are case-insensitive in atasm\n";
+ $line = ";;;;; $_ ; This assignment is an error in atasm";
+ next;
+ }
+
+# do this before we split out the label:
+ s/^\./\@/; # local label (dot in dasm, @ in atasm)
+
+ if(s/^([^:;\s]*):?(\s+)/$2/) {
+ $label = $1;
+ }
+
+ ($line, $comment) = split /;/, $_, 2;
+ next unless $line;
+
+ $line = do_subs($line);
+
+} continue {
+ if($linenum) {
+ print OUT "$linenum ";
+ $linenum += 10;
+ }
+
+ print OUT $label if $label;
+ print OUT $line if $line;
+ print OUT ";$comment" if $comment;
+ print OUT ($a8eol ? "\x9b" : "\n");
+}
diff --git a/src/col80_modified/cruft/dos_20s.atr b/src/col80_modified/cruft/dos_20s.atr
new file mode 100755
index 0000000..8016b73
--- /dev/null
+++ b/src/col80_modified/cruft/dos_20s.atr
Binary files differ
diff --git a/src/col80_modified/cruft/font.bin b/src/col80_modified/cruft/font.bin
new file mode 100644
index 0000000..d2fd3d4
--- /dev/null
+++ b/src/col80_modified/cruft/font.bin
Binary files differ
diff --git a/src/col80_modified/cruft/font.s b/src/col80_modified/cruft/font.s
new file mode 100644
index 0000000..78266ea
--- /dev/null
+++ b/src/col80_modified/cruft/font.s
@@ -0,0 +1,54 @@
+ .org 1000
+ ; Space ! " # etc (codes 32-63)
+ .byte $00,$04,$04,$04,$04,$00,$04,$00
+ .byte $00,$A0,$AA,$AE,$0A,$0E,$0A,$00
+ .byte $00,$40,$68,$82,$44,$28,$C2,$40
+ .byte $00,$C4,$64,$E4,$60,$C0,$40,$00
+ .byte $00,$44,$82,$82,$82,$82,$82,$44
+ .byte $00,$04,$A4,$4E,$E4,$44,$A0,$00
+ .byte $00,$00,$00,$0E,$00,$40,$40,$80
+ .byte $00,$02,$02,$04,$04,$08,$48,$00
+ .byte $00,$E4,$AC,$A4,$A4,$A4,$EE,$00
+ .byte $00,$EE,$22,$22,$EE,$82,$EE,$00
+ .byte $00,$AE,$A8,$AE,$E2,$22,$2E,$00
+ .byte $00,$EE,$82,$E2,$A4,$A4,$E4,$00
+ .byte $00,$EE,$AA,$EA,$AE,$A2,$EE,$00
+ .byte $00,$00,$00,$44,$00,$44,$04,$08
+ .byte $00,$20,$4E,$80,$4E,$20,$00,$00
+ .byte $00,$8C,$42,$22,$44,$80,$04,$00
+
+ ; @ A B C etc (codes 64-95)
+ .byte $00,$6E,$9A,$BA,$BE,$8A,$6A,$00
+ .byte $00,$C6,$A8,$C8,$A8,$A8,$C6,$00
+ .byte $00,$CE,$A8,$AC,$A8,$A8,$CE,$00
+ .byte $00,$E6,$88,$C8,$8A,$8A,$86,$00
+ .byte $00,$AE,$A4,$E4,$A4,$A4,$AE,$00
+ .byte $00,$2A,$2A,$2C,$2A,$2A,$CA,$00
+ .byte $00,$8A,$8E,$8E,$8A,$8A,$EA,$00
+ .byte $00,$C4,$AA,$AA,$AA,$AA,$A4,$00
+ .byte $00,$EE,$AA,$EA,$8A,$8A,$8E,$03
+ .byte $00,$C6,$A8,$AC,$C2,$A2,$AC,$00
+ .byte $00,$EA,$4A,$4A,$4A,$4A,$4E,$00
+ .byte $00,$AA,$AA,$AA,$AE,$AE,$4A,$00
+ .byte $00,$AA,$4A,$4E,$44,$44,$A4,$00
+ .byte $00,$EE,$28,$48,$88,$88,$E8,$0E
+ .byte $00,$8E,$82,$42,$42,$22,$22,$0E
+ .byte $00,$00,$40,$A0,$00,$00,$00,$0F
+
+ ; diamond, lowercase letters, control codes (codes 96-127)
+ .byte $00,$00,$00,$46,$E2,$4E,$0E,$00
+ .byte $00,$80,$80,$C6,$A8,$A8,$C6,$00
+ .byte $00,$20,$20,$6E,$AE,$A8,$6E,$00
+ .byte $00,$00,$C0,$86,$CA,$8E,$82,$0C
+ .byte $00,$80,$84,$80,$C4,$A4,$A4,$00
+ .byte $00,$08,$28,$0A,$2C,$2A,$2A,$C0
+ .byte $00,$40,$40,$4A,$4E,$4A,$4A,$00
+ .byte $00,$00,$00,$CE,$AA,$AA,$AE,$00
+ .byte $00,$00,$00,$C6,$AA,$C6,$82,$82
+ .byte $00,$00,$00,$6E,$88,$86,$8E,$00
+ .byte $00,$00,$40,$EA,$4A,$4A,$6E,$00
+ .byte $00,$00,$00,$AA,$AA,$AE,$4A,$00
+ .byte $00,$00,$00,$AA,$4A,$A6,$A2,$0C
+ .byte $00,$00,$04,$EE,$4E,$84,$EE,$00
+ .byte $40,$4E,$4C,$4E,$4A,$42,$42,$40
+ .byte $00,$28,$6C,$EE,$6C,$28,$00,$00
diff --git a/src/col80_modified/cruft/font2xbm.pl b/src/col80_modified/cruft/font2xbm.pl
new file mode 100644
index 0000000..3337139
--- /dev/null
+++ b/src/col80_modified/cruft/font2xbm.pl
@@ -0,0 +1,47 @@
+#!/usr/bin/perl -w
+
+use bytes;
+
+$name = "xbm";
+$width = 8;
+$height = 384;
+$cwidth = $width / 8;
+$cheight = $height / 8;
+
+print <<EOF;
+#define ${name}_width ${width}
+#define ${name}_height ${height}
+static unsigned char ${name}_bits[] = {
+EOF
+
+undef $/;
+$_ = <>;
+@inbytes = split "";
+
+# reverse bits, print 12 bytes/line
+
+$c = 0;
+for($i=0; $i<@inbytes; $i++) {
+ $byte = ord $inbytes[$i];
+ if(!$c) {
+ print " ";
+ }
+
+ printf "0x%02x", reverse_bits($byte);
+ if($i != $#inbytes) {
+ if($c == 12) {
+ print ",\n";
+ $c = 0;
+ } else {
+ print ", ";
+ $c++;
+ }
+ }
+}
+
+print " };\n";
+
+sub reverse_bits {
+ my $bitstr = reverse sprintf("%08b", $_[0]);
+ return eval "0b$bitstr";
+}
diff --git a/src/col80_modified/cruft/new_font.s b/src/col80_modified/cruft/new_font.s
new file mode 100644
index 0000000..f70ae8b
--- /dev/null
+++ b/src/col80_modified/cruft/new_font.s
@@ -0,0 +1,48 @@
+ .byte $00,$04,$04,$04,$04,$00,$04,$00
+ .byte $00,$A0,$AA,$AE,$0A,$0E,$0A,$00
+ .byte $00,$40,$68,$82,$44,$28,$C2,$40
+ .byte $00,$44,$E4,$84,$60,$80,$E0,$40
+ .byte $00,$44,$82,$82,$82,$82,$82,$44
+ .byte $00,$00,$A4,$44,$EE,$44,$A4,$00
+ .byte $00,$00,$00,$0E,$00,$40,$40,$80
+ .byte $00,$02,$02,$04,$04,$08,$48,$00
+ .byte $00,$E4,$AC,$A4,$A4,$A4,$EE,$00
+ .byte $00,$EE,$22,$22,$EE,$82,$EE,$00
+ .byte $00,$AE,$A8,$AE,$E2,$22,$2E,$00
+ .byte $00,$EE,$82,$E2,$A4,$A4,$E4,$00
+ .byte $00,$EE,$AA,$EA,$AE,$A2,$EE,$00
+ .byte $00,$00,$00,$44,$00,$44,$04,$08
+ .byte $00,$20,$4E,$80,$4E,$20,$00,$00
+ .byte $00,$8C,$42,$22,$44,$80,$04,$00
+ .byte $00,$6E,$9A,$BA,$BE,$8A,$6A,$00
+ .byte $00,$C6,$A8,$C8,$A8,$A8,$C6,$00
+ .byte $00,$CE,$A8,$AC,$A8,$A8,$CE,$00
+ .byte $00,$E6,$88,$C8,$8A,$8A,$86,$00
+ .byte $00,$AE,$A4,$E4,$A4,$A4,$AE,$00
+ .byte $00,$2A,$2A,$2C,$2A,$2A,$CA,$00
+ .byte $00,$8A,$8E,$8E,$8A,$8A,$EA,$00
+ .byte $00,$C4,$AA,$AA,$AA,$AA,$A4,$00
+ .byte $00,$EE,$AA,$EA,$8A,$8A,$8E,$03
+ .byte $00,$C6,$A8,$AC,$C2,$A2,$AC,$00
+ .byte $00,$EA,$4A,$4A,$4A,$4A,$4E,$00
+ .byte $00,$AA,$AA,$AA,$AE,$AE,$4A,$00
+ .byte $00,$AA,$4A,$4E,$44,$44,$A4,$00
+ .byte $00,$EE,$28,$48,$88,$88,$E8,$0E
+ .byte $00,$8E,$82,$42,$42,$22,$22,$0E
+ .byte $00,$00,$40,$A0,$00,$00,$00,$0F
+ .byte $00,$00,$0C,$42,$E6,$4A,$0E,$00
+ .byte $00,$80,$80,$C6,$A8,$A8,$C6,$00
+ .byte $00,$20,$26,$6A,$AE,$A8,$6E,$00
+ .byte $00,$00,$C0,$86,$CA,$8E,$82,$0C
+ .byte $00,$80,$84,$80,$C4,$A4,$A4,$00
+ .byte $00,$08,$28,$0A,$2C,$2A,$2A,$C0
+ .byte $00,$40,$40,$4A,$4E,$4A,$4A,$00
+ .byte $00,$00,$00,$CE,$AA,$AA,$AE,$00
+ .byte $00,$00,$00,$C6,$AA,$C6,$82,$83
+ .byte $00,$00,$00,$6E,$88,$86,$8E,$00
+ .byte $00,$00,$40,$EA,$4A,$4A,$6E,$00
+ .byte $00,$00,$00,$AA,$AA,$AE,$4A,$00
+ .byte $00,$00,$00,$AA,$4A,$A6,$A2,$0C
+ .byte $00,$06,$04,$E4,$48,$84,$E4,$06
+ .byte $40,$4C,$44,$44,$42,$44,$44,$4C
+ .byte $00,$08,$5C,$AE,$0C,$08,$00,$00
diff --git a/src/col80_modified/cruft/new_font.xbm b/src/col80_modified/cruft/new_font.xbm
new file mode 100644
index 0000000..a7fab38
--- /dev/null
+++ b/src/col80_modified/cruft/new_font.xbm
@@ -0,0 +1,35 @@
+#define font_width 8
+#define font_height 384
+static unsigned char font_bits[] = {
+ 0x00, 0x20, 0x20, 0x20, 0x20, 0x00, 0x20, 0x00, 0x00, 0x05, 0x55, 0x75,
+ 0x50, 0x70, 0x50, 0x00, 0x00, 0x02, 0x16, 0x41, 0x22, 0x14, 0x43, 0x02,
+ 0x00, 0x22, 0x27, 0x21, 0x06, 0x01, 0x07, 0x02, 0x00, 0x22, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x22, 0x00, 0x00, 0x25, 0x22, 0x77, 0x22, 0x25, 0x00,
+ 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, 0x02, 0x01, 0x00, 0x40, 0x40, 0x20,
+ 0x20, 0x10, 0x12, 0x00, 0x00, 0x27, 0x35, 0x25, 0x25, 0x25, 0x77, 0x00,
+ 0x00, 0x77, 0x44, 0x44, 0x77, 0x41, 0x77, 0x00, 0x00, 0x75, 0x15, 0x75,
+ 0x47, 0x44, 0x74, 0x00, 0x00, 0x77, 0x41, 0x47, 0x25, 0x25, 0x27, 0x00,
+ 0x00, 0x77, 0x55, 0x57, 0x75, 0x45, 0x77, 0x00, 0x00, 0x00, 0x00, 0x22,
+ 0x00, 0x22, 0x20, 0x10, 0x00, 0x04, 0x72, 0x01, 0x72, 0x04, 0x00, 0x00,
+ 0x00, 0x31, 0x42, 0x44, 0x22, 0x01, 0x20, 0x00, 0x00, 0x76, 0x59, 0x5d,
+ 0x7d, 0x51, 0x56, 0x00, 0x00, 0x63, 0x15, 0x13, 0x15, 0x15, 0x63, 0x00,
+ 0x00, 0x73, 0x15, 0x35, 0x15, 0x15, 0x73, 0x00, 0x00, 0x67, 0x11, 0x13,
+ 0x51, 0x51, 0x61, 0x00, 0x00, 0x75, 0x25, 0x27, 0x25, 0x25, 0x75, 0x00,
+ 0x00, 0x54, 0x54, 0x34, 0x54, 0x54, 0x53, 0x00, 0x00, 0x51, 0x71, 0x71,
+ 0x51, 0x51, 0x57, 0x00, 0x00, 0x23, 0x55, 0x55, 0x55, 0x55, 0x25, 0x00,
+ 0x00, 0x77, 0x55, 0x57, 0x51, 0x51, 0x71, 0xc0, 0x00, 0x63, 0x15, 0x35,
+ 0x43, 0x45, 0x35, 0x00, 0x00, 0x57, 0x52, 0x52, 0x52, 0x52, 0x72, 0x00,
+ 0x00, 0x55, 0x55, 0x55, 0x75, 0x75, 0x52, 0x00, 0x00, 0x55, 0x52, 0x72,
+ 0x22, 0x22, 0x25, 0x00, 0x00, 0x77, 0x14, 0x12, 0x11, 0x11, 0x17, 0x70,
+ 0x00, 0x71, 0x41, 0x42, 0x42, 0x44, 0x44, 0x70, 0x00, 0x00, 0x02, 0x05,
+ 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x30, 0x42, 0x67, 0x52, 0x70, 0x00,
+ 0x00, 0x01, 0x01, 0x63, 0x15, 0x15, 0x63, 0x00, 0x00, 0x04, 0x64, 0x56,
+ 0x75, 0x15, 0x76, 0x00, 0x00, 0x00, 0x03, 0x61, 0x53, 0x71, 0x41, 0x30,
+ 0x00, 0x01, 0x21, 0x01, 0x23, 0x25, 0x25, 0x00, 0x00, 0x10, 0x14, 0x50,
+ 0x34, 0x54, 0x54, 0x03, 0x00, 0x02, 0x02, 0x52, 0x72, 0x52, 0x52, 0x00,
+ 0x00, 0x00, 0x00, 0x73, 0x55, 0x55, 0x75, 0x00, 0x00, 0x00, 0x00, 0x63,
+ 0x55, 0x63, 0x41, 0xc1, 0x00, 0x00, 0x00, 0x76, 0x11, 0x61, 0x71, 0x00,
+ 0x00, 0x00, 0x02, 0x57, 0x52, 0x52, 0x76, 0x00, 0x00, 0x00, 0x00, 0x55,
+ 0x55, 0x75, 0x52, 0x00, 0x00, 0x00, 0x00, 0x55, 0x52, 0x65, 0x45, 0x30,
+ 0x00, 0x60, 0x20, 0x27, 0x12, 0x21, 0x27, 0x60, 0x02, 0x32, 0x22, 0x22,
+ 0x42, 0x22, 0x22, 0x32, 0x00, 0x10, 0x3a, 0x75, 0x30, 0x10, 0x00, 0x00 };
diff --git a/src/col80_modified/cruft/test.atr b/src/col80_modified/cruft/test.atr
new file mode 100755
index 0000000..0127b33
--- /dev/null
+++ b/src/col80_modified/cruft/test.atr
Binary files differ
diff --git a/src/col80_modified/cruft/xbm2font.pl b/src/col80_modified/cruft/xbm2font.pl
new file mode 100644
index 0000000..758d57e
--- /dev/null
+++ b/src/col80_modified/cruft/xbm2font.pl
@@ -0,0 +1,29 @@
+#!/usr/bin/perl -w
+
+use bytes;
+
+$c = 0;
+
+while(<>) {
+ next unless @bytes = (/0x([0-9a-fA-F]{2})/g);
+ for(@bytes) {
+ if(!($c % 8)) {
+ print " .byte ";
+ }
+
+ printf "\$%02X", reverse_bits(hex $_);
+
+ if(($c % 8 == 7) || ($c == $#bytes)) {
+ print "\n";
+ $c = 0;
+ } else {
+ print ",";
+ $c++;
+ }
+ }
+}
+
+sub reverse_bits {
+ my $bitstr = reverse sprintf("%08b", $_[0]);
+ return eval "0b$bitstr";
+}