|
Subject: [stella] 20 columns of almost-readable text From: "B. Watson" <atari@xxxxxxxxxxxxxx> Date: Thu, 13 Sep 2001 19:25:47 -0400 (EDT) |
This is what I spent last night doing, to get my mind off the terrorist
bombings (there's nothing I can do to change the situation right now, so
obsessing over it isn't helping me sleep...)
This may have been done before, I hope not though (my ego wants to think
I invented something new, even if my id doubts it :)
Anyway, what I did, was take the old 6digit.asm from the archives and modify
it so that it only draws 5 `digits', starting around color clock 40. Each of
the `digits' is actually 2 characters wide, in a 4-bit wide font. Once I got
that working, I wrote another routine that does the same thing, starting at
about color clock 80, then called the routines on alternate frames. This gives
me a 20 character wide display area, from clocks 40 to 120, with flickering.
I did try displaying all 6 digits each frame, for 12 digits (*2 4x5 characters
per digit, would have been 24 characters), but couldn't quite get the timing
right for both frames... I may try adding the extra digit (2 chars) to one
frame or the other, for 22 characters.
The display is something like this:
Even-numbered frames:
+----------------------------------------+
| 0011001100 |
Odd-numbered frames:
+----------------------------------------+
| 0011001100 |
each dash represents 4 color clocks. the 0's and 1's are which player is being
displayed (NUSIZ0 is 3, NUSIZ1 is 1).
Next I created a 4x5 font with ASCII characters 41-90 (right paren thru Z),
and a blank character for a space. I wrote a not-very-optimized subroutine
that converts an ASCII string in ROM (or, I suppose, in RAM...) to 25 bytes
of display data, 5 bytes per every 2 ASCII characters. I called it once per
frame, so I could display any arbitrary 20-character string in 2 frames...
Then I tried incrementing the message pointer every 4 frames. Now I've got a
20-character wide marquee that scrolls a 128-byte message (the last 20 bytes
of which need to be spaces).
Amazingly, it worked on a real Atari the first time I tried it. So I decided
to get cute, and try to display 2 text messages, by calling the character
generation routine again during the kernel. It turns out that my non-optimised
code takes approximately 30 scanlines to execute. The display routines display
each of the 5 bytes twice, plus one empty scanline (11 scanlines total), so
I could have 5 lines of widely-spaced text for a total of 175 scanlines.
The flicker looks worse in an emulator than it does on a TV set, but it's still
pretty ugly-looking. 20x5 characters isnt much of a text display, and the 4x5
font makes it even harder to read. However... I did get the 2600 to do
something I didn't think it could do at all, and the scrolling marquee would be
kind of cool for a Star Raiders type of game (scrolling messages reading
`SHIELDS DAMAGED...PHOTONS DESTROYED...STARBASE UNDER ATTACK...' etc. etc.)
Hrmmm... with some modifications, and a lot more RAM usage, it might be
possible to do 20x4 lines of closely-spaced text, vertically. This would be
44 scanlines tall, but would eat up 100 bytes of RAM... Of course those 100
bytes are re-usable, you only need them from the time you calculate the
graphics data to the time you're done displaying it.. This could be something
like the `text window' in the graphics modes on the Atari 400/800 machines.
Another idea I had was a one-line message window, that scrolls *vertically*
instead of horizontal marquee-style. This would be tougher to do, but still
should only require 25 bytes of video RAM, plus 2 pointers (to the current
message, and to the old one that's being scrolled away).
Basically I'm just throwing out ideas, and the code... if anybody finds a use
for this, go for it. The code is not so great, could stand to be cleaned up
and made smarter (it *should* be possible to use the same kernel to display
either the left or right frame, but every time I tried I couldn't make the
timing come out right)
Enjoy,
Brian
---
If a trainstation is the place where trains stop, what is a workstation?
---begin marquee.asm---
; marquee.asm
; by B. Watson <atari@xxxxxxxxxxxxxx>
; dasm marquee.asm -omarquee.bin -f3 -v3
; Draws a 20-character scrolling marquee, with too much flicker :(
; Tested on a real Atari 2600
; Tested on z26 v1.46 on a windows machine
; Tested on xstella 1.1 on a linux machine
processor 6502
include "vcs.h"
seg.u data
org $80
framectr ds 1
digit0 ds 5
digit1 ds 5
digit2 ds 5
digit3 ds 5
digit4 ds 5
tmp0 ; is same var as tmp1
tmp1 ds 1
tmp2 ds 1
tmp3 ds 1
count1 ds 1
msgptr ds 2
fontptr ds 2
scrollctr ds 1
echo *-$80,"bytes of zero page used."
seg code
org $F000
sei
cld
ldx #$ff
txs
lda #0
iloop
sta 0,x
bne iloop
lda #10
sta COLUP0
sta COLUP1
lda #$B0
sta COLUPF
lda #3
sta NUSIZ0
lda #1
sta NUSIZ1
sta CTRLPF
; the main_loop is nasty: I just unrolled it so each time thru the loop
; draws 2 frames, each with its own separate, nearly-identical kernel.
; In a real game I'd want to figure out a way to be more clever.
main_loop
lda #2
sta VSYNC ; start blanking
sta WSYNC
sta WSYNC
lda #44
sta TIM64T ; go ahead & set timer
lda #0
sta WSYNC
sta VSYNC ; 3 WSYNC's, then turn off VSYNC
inc framectr
lda framectr
;sta COLUPF ; flashing colors make it even harder to read!
and #$03
bne skip_scroll
inc scrollctr
lda scrollctr
and #$7F
sta scrollctr
skip_scroll
lda #<message
adc scrollctr
sta msgptr
lda #>message
sta msgptr+1
jsr decode_message ; yowza!
l_wait_timer
lda INTIM
bne l_wait_timer ; busy-wait for timer to expire
sta WSYNC
l_kernel
sta WSYNC
repeat 14
nop
repend
sta $2000+RESP0 ; 14*2+4=32
sta WSYNC
repeat 16
nop
repend
sta RESP1 ; 16*2+3 = 35
sta HMCLR
lda #%10100000
sta HMP1
lda #%10010000;
sta HMP0
sta WSYNC
sta HMOVE
sta WSYNC
lda #$FF
sta PF2
lda #$07
sta PF1
sta WSYNC
sta WSYNC
lda #$04
sta PF1
lda #$0
sta PF2
jsr draw_lhs
sta WSYNC
lda #$07
sta PF1
lda #$FF
sta PF2
sta WSYNC
sta WSYNC
lda #$00
sta PF1
sta PF2
lda #<email
sta msgptr
lda #>email
sta msgptr+1
jsr decode_message
jsr draw_lhs
ldy #139
l_blank_pf
sta WSYNC
dey
bne l_blank_pf
end_kernel
lda #37
sta TIM64T
l_overscan
l_finish_overscan
lda INTIM
bne l_finish_overscan
; begin right frame
lda #2
sta VSYNC ; start blanking
sta WSYNC
sta WSYNC
lda #44
sta TIM64T ; go ahead & set timer
lda #0
sta WSYNC
sta VSYNC ; 3 WSYNC's, then turn off VSYNC
lda #<[message+10]
adc scrollctr
sta msgptr
lda #>[message+10]
sta msgptr+1
jsr decode_message ; yowza!
r_wait_timer
lda INTIM
bne r_wait_timer ; busy-wait for timer to expire
sta WSYNC
r_kernel
sta WSYNC
repeat 21
nop
repend
sta $2000+RESP0 ; 13*2+4=30
sta WSYNC
repeat 23
nop
repend
sta RESP1 ; 14*2+3 = 31
sta HMCLR
lda #%11000000
sta HMP1
lda #%10110000;
sta HMP0
sta WSYNC
sta HMOVE
sta WSYNC
lda #$FF
sta PF2
lda #$07
sta PF1
sta WSYNC
sta WSYNC
lda #$04
sta PF1
lda #$0
sta PF2
jsr draw_rhs
lda #0
sta GRP0
sta GRP1
sta WSYNC
lda #$07
sta PF1
lda #$FF
sta PF2
sta WSYNC
sta WSYNC
lda #$00
sta PF1
sta PF2
lda #<[email+10]
sta msgptr
lda #>[email+10]
sta msgptr+1
jsr decode_message
jsr draw_rhs
ldy #139
blank_pf
sta WSYNC
dey
bne blank_pf
r_end_kernel
lda #37
sta TIM64T
r_overscan
r_finish_overscan
lda INTIM
bne r_finish_overscan
jmp main_loop
; subroutines
decode1byte ; A holds ASCII char
; on exit, (fontptr) hold pointer to appropriate character in ROM font table
sec
sbc #40 ; de-ASCIIfy (our ASCII subset starts at character 41)
bcs valid_ascii
lda #0 ; if we don't have the character, just print a space
valid_ascii
sta tmp1
asl ; a=a*2
asl ; a=a*2 again
clc
adc tmp1 ; now a=(original a)*5
sta fontptr ; lo byte only, charset is <256 bytes!
rts
decode2chars ; (msgptr),y is ASCII character 1, (msgptr),y+1 is 2nd
; X is index into character RAM
lda #>font
sta fontptr+1 ; set up hi-byte
sty tmp2 ; hang on to it
stx tmp3 ; tmp3 is index into character RAM
do_1st_char
;ldy tmp2
lda (msgptr),y
jsr decode1byte
ldy #4
store_hi_nybble
lda (fontptr),y
sta 0,x
inx
dey
bpl store_hi_nybble
do_2nd_char
ldy tmp2
iny
; sty tmp2
ldx tmp3
lda (msgptr),y
jsr decode1byte
ldy #4
store_lo_nybble
lda (fontptr),y
lsr
lsr
lsr
lsr
ora 0,x
sta 0,x
inx
dey
bpl store_lo_nybble
stx tmp3 ; maybe not need
ldy tmp2 ; restore Y to what it was before we were called
rts
decode_message ; (msgptr) should point to message
ldx #digit0 ; X will be index into character RAM
ldy #0 ; Y will be index into ASCII string
do_string
jsr decode2chars ; each call eats up 2 characters of string,
iny ; so we have 2 INY's here to keep our place.
iny
cpy #10
bne do_string
rts
draw_lhs
ldx #4
stx count1
; the drawloops actually do all the work. Again, I just unrolled them, so
; each time thru the loop draws the same thing on 2 consecutive scanlines.
l_drawloop
sta WSYNC
ldx count1 ; 3
lda digit0,x ; +4 = 7
sta GRP0 ; +3 = 10
lda digit1,x ; + 4 = 14
sta GRP1 ; +3 = 17
lda digit2,x ; +4 = 21
sta tmp0 ; +3 = 24
lda digit3,x ; +4 = 28
tay ; + 2 = 30
lda digit4,x ; + 4 = 34
ldx tmp0 ; + 3 = 37
stx GRP0 ; +3 = 40
sty GRP1 ; +3 = 43
sta GRP0 ; +3 = 46
sta WSYNC
ldx count1 ; 3
lda digit0,x ; +4 = 7
sta GRP0 ; +3 = 10
lda digit1,x ; + 4 = 14
sta GRP1 ; +3 = 17
lda digit2,x ; +4 = 21
sta tmp0 ; +3 = 24
lda digit3,x ; +4 = 28
tay ; + 2 = 30
lda digit4,x ; + 4 = 34
ldx tmp0 ; + 3 = 37
stx GRP0 ; +3 = 40
sty GRP1 ; +3 = 43
sta GRP0 ; +3 = 46
dec count1 ; +5 = 51
bpl l_drawloop ; +2 = 53
sta WSYNC
lda #0
sta GRP0
sta GRP1
rts
draw_rhs
ldx #4
stx count1
r_drawloop
sta WSYNC
repeat 6
nop
repend
ldx count1 ; 3
lda digit0,x ; +4 = 7
sta GRP0 ; +3 = 10
lda digit1,x ; + 4 = 14
sta GRP1 ; +3 = 17
lda digit2,x ; +4 = 21
sta tmp0 ; +3 = 24
lda digit3,x ; +4 = 28
tay ; + 2 = 30
lda digit4,x ; + 4 = 34
ldx tmp0 ; + 3 = 37
stx GRP0 ; +3 = 40
sty GRP1 ; +3 = 43
sta GRP0 ; +3 = 46
sta WSYNC
repeat 6
nop
repend
ldx count1 ; 3
lda digit0,x ; +4 = 7
sta GRP0 ; +3 = 10
lda digit1,x ; + 4 = 14
sta GRP1 ; +3 = 17
lda digit2,x ; +4 = 21
sta tmp0 ; +3 = 24
lda digit3,x ; +4 = 28
tay ; + 2 = 30
lda digit4,x ; + 4 = 34
ldx tmp0 ; + 3 = 37
stx GRP0 ; +3 = 40
sty GRP1 ; +3 = 43
sta GRP0 ; +3 = 46
dec count1 ; +5 = 51
bpl r_drawloop ; +2 = 53
sta WSYNC
lda #0
sta GRP0
sta GRP1
rts
echo *-$F000,"bytes of code"
org $F800
font
; include "4x5font.h"
font_space
byte %00000000
byte %00000000
byte %00000000
byte %00000000
byte %00000000
font_rparen
byte %01000000
byte %00100000
byte %00100000
byte %00100000
byte %01000000
font_star
byte %00000000
byte %10100000
byte %01000000
byte %10100000
byte %00000000
font_plus
byte %00000000
byte %01000000
byte %11100000
byte %01000000
byte %00000000
font_comma
byte %00000000
byte %00000000
byte %00000000
byte %01000000
byte %10000000
font_dash
byte %00000000
byte %00000000
byte %11100000
byte %00000000
byte %00000000
font_dot
byte %00000000
byte %00000000
byte %00000000
byte %00000000
byte %01000000
font_slash
byte %00100000
byte %00100000
byte %01000000
byte %10000000
byte %10000000
font_0
byte %01000000
byte %10100000
byte %11100000
byte %10100000
byte %01000000
font_1
byte %01000000
byte %11000000
byte %01000000
byte %01000000
byte %11100000
font_2
byte %11000000
byte %00100000
byte %01000000
byte %10000000
byte %11100000
font_3
byte %11000000
byte %00100000
byte %01000000
byte %00100000
byte %11000000
font_4
byte %00100000
byte %10100000
byte %11100000
byte %00100000
byte %00100000
font_5
byte %11100000
byte %10000000
byte %01000000
byte %00100000
byte %11000000
font_6
byte %01100000
byte %10000000
byte %11100000
byte %10100000
byte %11000000
font_7
byte %11100000
byte %00100000
byte %01000000
byte %10000000
byte %10000000
font_8
byte %11100000
byte %10100000
byte %01000000
byte %10100000
byte %11100000
font_9
byte %01100000
byte %10100000
byte %11100000
byte %00100000
byte %11000000
font_colon
byte %00000000
byte %01000000
byte %00000000
byte %01000000
byte %00000000
font_semi
byte %00000000
byte %01000000
byte %00000000
byte %01000000
byte %10000000
font_less
byte %00100000
byte %01000000
byte %10000000
byte %01000000
byte %00100000
font_equal
byte %00000000
byte %11100000
byte %00000000
byte %11100000
byte %00000000
font_greater
byte %10000000
byte %01000000
byte %00100000
byte %01000000
byte %10000000
font_ques
byte %01100000
byte %10010000
byte %00100000
byte %00000000
byte %00100000
font_at
byte %01000000
byte %10100000
byte %10100000
byte %10000000
byte %01100000
font_A
byte %01000000
byte %10100000
byte %11100000
byte %10100000
byte %10100000
font_B
byte %11000000
byte %10100000
byte %11000000
byte %10100000
byte %11000000
font_C
byte %01100000
byte %10000000
byte %10000000
byte %10000000
byte %01100000
font_D
byte %11000000
byte %10100000
byte %10100000
byte %10100000
byte %11000000
font_E
byte %11100000
byte %10000000
byte %11000000
byte %10000000
byte %11100000
font_F
byte %11100000
byte %10000000
byte %11000000
byte %10000000
byte %10000000
font_G
byte %01100000
byte %10000000
byte %10100000
byte %10100000
byte %01100000
font_H
byte %10100000
byte %10100000
byte %11100000
byte %10100000
byte %10100000
font_I
byte %11100000
byte %01000000
byte %01000000
byte %01000000
byte %11100000
font_J
byte %01100000
byte %00100000
byte %00100000
byte %10100000
byte %01100000
font_K
byte %10100000
byte %10100000
byte %11000000
byte %10100000
byte %10010000
font_L
byte %10000000
byte %10000000
byte %10000000
byte %10000000
byte %11100000
font_M
byte %10100000
byte %11100000
byte %11100000
byte %10100000
byte %10100000
font_N
byte %11000000
byte %10100000
byte %10100000
byte %10100000
byte %10100000
font_O
byte %01000000
byte %10100000
byte %10100000
byte %10100000
byte %01000000
font_P
byte %11000000
byte %10100000
byte %11000000
byte %10000000
byte %10000000
font_Q
byte %01000000
byte %10100000
byte %10100000
byte %01000000
byte %00100000
font_R
byte %11000000
byte %10100000
byte %11000000
byte %10100000
byte %10100000
font_S
byte %01100000
byte %10000000
byte %01000000
byte %00100000
byte %11000000
font_T
byte %11100000
byte %01000000
byte %01000000
byte %01000000
byte %01000000
font_U
byte %10100000
byte %10100000
byte %10100000
byte %10100000
byte %11100000
font_V
byte %10100000
byte %10100000
byte %10100000
byte %11000000
byte %10000000
font_W
byte %10100000
byte %10100000
byte %11100000
byte %11100000
byte %10100000
font_X
byte %10100000
byte %10100000
byte %01000000
byte %10100000
byte %10100000
font_Y
byte %10100000
byte %10100000
byte %01000000
byte %01000000
byte %01000000
font_Z
byte %11100000
byte %00100000
byte %01000000
byte %10000000
byte %11100000
org $F900
message ; should begin with 20 spaces (FIXME: get rid of this requirement)
byte " "
byte "HOW DO YOU LIKE "
byte "THIS UGLY FLICKE"
byte "RING SCROLLING M"
byte "ARQUEE? I HOPE I"
byte "T DOESNT GIVE YO"
byte "U A HEADACHE LIK"
byte "E IT GAVE ME"
repeat 128
byte " "
repend
email byte "ATARI@xxxxxxxxxxxxxx"
echo *-$F800,"bytes of data"
org $FFFC
word $F000
word $F000
Attachment:
marquee.bin
Description: Binary data
| Current Thread |
|---|
|
| <- Previous | Index | Next -> |
|---|---|---|
| [stella] Note to hotmail users, Glenn Saunders | Thread | Ten digit playfield routine, was: [, Jake Patterson |
| Re: [stella] How about 6800?, Piero Cavina | Date | Ten digit playfield routine, was: [, Jake Patterson |
| Month |