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 |