Jump to content
IGNORED

6502 asm wizards needed: color conversion routine NTSC -> PAL


SvOlli

Recommended Posts

Hey there!

 

I'm trying to paint a rainbow effect on a PAL console. Since the colors are ordered very "strange" on a PAL console, I tried to write some code to "reorder" the color table for me. It didn't need to be a mapping NTSC -> PAL as close as possible, it should just a one nice rainbow, not two interlacing.

 

A bit about the code:

The X register is the base for color calculation. Painting a "bad" rainbow would look something like this:

tax
asl
sta COLUPF

This way each line (not just ever other) gets a new color.

 

Here's what I came up with so far:

txa
; optional color conversion ntsc -> pal
; adds $1b = 27 bytes 
; 2 %0010 <- 2 %0010
; 4 %0100 <- 3 %0011
; 6 %0110 <- 4 %0100
; 8 %1000 <- 5 %0101
; A %1010 <- 6 %0110
; C %1100 <- 7 %0111
;
; D %1101 <- 8 %1000
; B %1011 <- 9 %1001
; 9 %1001 <- A %1010
; 7 %0111 <- B %1011
; 5 %0101 <- C %1100
; 3 %0011 <- D %1101
and #$07
sta $82
txa
cmp #$c0 ; <- this should be and #$7f : cmp #$40, but X is always > $80 while drawing, saving 2 bytes
bcs @upper
and #$38
asl
sbc #$0f ; <- shound be: sec : sbc #$10, but C is always 0
bpl @skip ; <- always true because of and #$38
@upper:
and #$B8
asl
sta $83
lda #$68
sbc $83
@skip:
ora $82
; optional color conversion end
asl
sta COLUPF

Anyone got an idea on how to do it with less bytes of rom?

 

Greetings,

SvOlli

 

[Edit: added some more comments]

Edited by SvOlli
Link to comment
Share on other sites

If you are just converting colors from NTSC to PAL, then maybe you can do something like this:

 

 

;NTSC $0x = PAL $0x no change
;NTSC $1x = PAL $2x <-- ($10to$18 PAL $30to$38) ($1Ato$1F PAL $2Ato$2F)
;NTSC $2x = PAL $2x no change
;NTSC $3x = PAL $4x +$10
;NTSC $4x = PAL $6x +$20
;NTSC $5x = PAL $8x +$30
;NTSC $6x = PAL $Ax +$40
;NTSC $7x = PAL $Cx +$50
;NTSC $8x = PAL $Dx +$50
;NTSC $9x = PAL $Bx +$20
;NTSC $Ax = PAL $9x -$10
;NTSC $Bx = PAL $7x -$40
;NTSC $Cx = PAL $5x -$70
;NTSC $Dx = PAL $3x -$A0
;NTSC $Ex = PAL $3x <-- -$B0
;NTSC $Fx = PAL $2x <-- -$D0


 txa ; holds current NTSC color
 lsr
 lsr
 lsr
 lsr
 tay
 txa
 eor ColTabPal,Y ; color is now PAL
 asl
 sta COLUPF



ColTabPal:
 .byte $00 ; $0x
 .byte $30 ; $2x
 .byte $00 ; $2x
 .byte $70 ; $4x
 .byte $20 ; $6x
 .byte $D0 ; $8x
 .byte $C0 ; $Ax
 .byte $B0 ; $Cx
 .byte $50 ; $Dx
 .byte $20 ; $Bx
 .byte $30 ; $9x
 .byte $C0 ; $7x
 .byte $90 ; $5x
 .byte $E0 ; $3x
 .byte $D0 ; $3x
 .byte $D0 ; $2x

 

I got the color equates from SeaGtGruff, and added a few notes from someone else who said yellow ($10 to $18) was closer in $3x then $2x.

 

 

I just whipped up this EOR table right now, and it doesn't account for that odd ball case with the yellow. Everything else should work reasonably well though. Maybe you can overlap the data table with something to save a few more bytes.

Link to comment
Share on other sites

I'm trying to paint a rainbow effect on a PAL console. Since the colors are ordered very "strange" on a PAL console, I tried to write some code to "reorder" the color table for me. It didn't need to be a mapping NTSC -> PAL as close as possible, it should just a one nice rainbow, not two interlacing.

If you just want to do a rainbow effect in PAL without worrying about mapping the NTSC palette to the PAL palette, just skip every other hue in increasing order, then skip every other hue in decreasing order:

 

Increasing:

$2x

$4x

$6x

$8x

$Ax

$Cx

 

Decreasing:

$Dx

$Bx

$9x

$7x

$5x

$3x

 

This assumes you don't need/want to include the gray shades ($0x and $1x, as well as $Ex and $Fx).

 

So a PAL rainbow effect could be programmed as follows:

 

; Taste the PAL Rainbow!
; Version 1 - No Shades of Gray Allowed

  PROCESSOR 6502

VSYNC			 = $00
VBLANK			 = $01
WSYNC			 = $02
COLUBK			 = $09
PF0				 = $0D
PF1				 = $0E
PF2				 = $0F
AUDV0			 = $19
AUDV1			 = $1A
GRP0				 = $1B
GRP1				 = $1C
ENAM0			 = $1D
ENAM1			 = $1E
ENABL			 = $1F
TIM64T			 = $0296
TIMINT			 = $0285

first_color		 = $80
line_color		 = $81
hue_increment	 = $82

  ORG $F800

Boot_Routine

  CLD

  LDA #0
  STA PF0
  STA PF1
  STA PF2
  STA AUDV0
  STA AUDV1
  STA GRP0
  STA GRP1
  STA ENAM0
  STA ENAM1
  STA ENABL

  LDA #$0E
  STA first_color

Vertical_Blank

  LDA #2
  STA VBLANK

  LDA #32*76/64
  STA TIM64T

Front_Porch

  BIT TIMINT
  BPL Front_Porch

  STA WSYNC

  LDA #2
  STA VSYNC
  STA WSYNC
  STA WSYNC
  STA WSYNC

  LDA #0
  STA VSYNC

  LDA #46*76/64
  STA TIM64T

  LDA #$10
  STA hue_increment

  LDA first_color
  AND #$10
  BEQ Load_Color

  LDA #$D0
  STA hue_increment

Load_Color

  LDA first_color

  JSR Next_Color

  STY first_color
  STY line_color

Back_Porch

  BIT TIMINT
  BPL Back_Porch

  STA WSYNC

  LDA #0
  STA VBLANK

  LDX #230

Active_Video

  LDA line_color
  STA COLUBK

  JSR Next_Color

  STY line_color
  STY WSYNC

  DEX
  BNE Active_Video

  JMP Vertical_Blank

Next_Color

  CLC
  ADC #$02
  TAY

  AND #$0F
  BEQ Next_Hue
  RTS

Next_Hue

  TYA
  CLC
  ADC hue_increment
  TAY

  BIT hue_increment
  BMI Decreasing_Hues

  CPY #$E0
  BEQ Start_Decreasing
  RTS

Start_Decreasing

  LDY #$D0
  STY hue_increment
  RTS

Decreasing_Hues

  CPY #$10
  BEQ Start_Increasing
  RTS

Start_Increasing

  LDA #$10
  STA hue_increment

  LDY #$20
  RTS

  ORG $FFFC

  WORD Boot_Routine
  WORD Boot_Routine
END

 

It isn't very elegant code, and there's probably a better way to do it, but it works!

Taste_the_PAL_Rainbow.asm

Taste_the_PAL_Rainbow.asm.bin

Link to comment
Share on other sites

First of all: thanks, you two!

 

If you just want to do a rainbow effect in PAL without worrying about mapping the NTSC palette to the PAL palette, just skip every other hue in increasing order, then skip every other hue in decreasing order:

[...]

It isn't very elegant code, and there's probably a better way to do it, but it works!

I don't care about elegant, it just has to work in less bytes. icon_winking.gif Anyway, I tried to implement that inside my code and it took up slightly more than my "algorithm".

 

I took your code, and merged it with mine to get an example on how the code is intended to be used.

 

If you are just converting colors from NTSC to PAL, then maybe you can do something like this:

[...]

I just whipped up this EOR table right now, and it doesn't account for that odd ball case with the yellow. Everything else should work reasonably well though. Maybe you can overlap the data table with something to save a few more bytes.

That's an appoach that beat my code by 5 bytes, taking into account that the table only converts non-grey colors (on the PAL side: $00-$1f, $e0-$ff), and therefore only uses 12 bytes instead of 16.

 

I attached the code of a non-converting version as a template, a "port" of omegamatrix's idea and my original code for comparison. They print out the size of the code used in the marked sections during assembly.

omegamatrix1.asm

svolli1.asm

svolli2.asm

Link to comment
Share on other sites

Haven't really looked at the code, but just use a LUT

A special form of LUT is what omegamatrix suggested, and it beats my solution in the test environment, but unfortunately not in the real code. icon_sad.gif

 

As the main goal is to minimize the number of bytes in ROM, a generic LUT wouldn't cut it.

Link to comment
Share on other sites

I should have grabbed the color after the shift, so here is a new version. Also, it is optimized for a more rainbow PAL palette, and not every color is there. Finally I trash Y, but reload it after.

 

 

 txa
 asl
 pha
 lsr
 lsr
 lsr
 lsr
 tay  ; trash Y
 pla
 eor  ColPalTab-2,Y
 sta  COLUPF
 ldy  #0  ; reload Y with zero

ColPalTab:
 .byte $00
 .byte $70
 .byte $20
 .byte $D0
 .byte $C0
 .byte $B0
 .byte $50
 .byte $20
 .byte $30
 .byte $C0
 .byte $90
 .byte $E0

Link to comment
Share on other sites

That looks similar to some old code of mine, for scrolling rainbow bars:

 

ColorTab
   byte $20
   byte $40
   byte $60
   byte $80
   byte $A0
   byte $C0

   byte $D0
   byte $B0
   byte $90
   byte $70
   byte $50
   byte $30

   byte $20
   byte $40
   byte $60
   byte $80

shyKernel
   ldx #LINES-1
shyKernelLoop

   txa
   adc frame
   tay
   and #$0F
   sta temp+1
   tya
   lsr
   lsr
   lsr
   lsr
   tay
   lda ColorTab,Y
   ora temp+1
   sta WSYNC

   sta COLUBK

   dex
   bne shyKernelLoop

Link to comment
Share on other sites

You can also preserve Y, but it costs and extra byte as well as a temp register.

 

 

 TXA
 PHA ; save X
 ASL
 PHA
 LSR
 LSR
 LSR
 LSR
 TAX ; trash X instead
 PLA
 EOR ColPalTab-2,X
 STA COLUPF
 PLA ; reload X value
 TAX

 

 

Or, you could use the stack pointer, but that would require resetting it if you doing an JSR's.

Link to comment
Share on other sites

I managed to scape off 4 bytes in my version:

  txa
; 2 %0010 <- 2 %0010
; 4 %0100 <- 3 %0011
; 6 %0110 <- 4 %0100
; 8 %1000 <- 5 %0101
; A %1010 <- 6 %0110
; C %1100 <- 7 %0111
  and #$07
  sta $82
  txa
  asl ; a > $80 => sec
  bmi @upper
  and #$70
  sbc #$10
  bpl @skip
@upper:
; D %1101 <- 8 %1000
; B %1011 <- 9 %1001
; 9 %1001 <- A %1010
; 7 %0111 <- B %1011
; 5 %0101 <- C %1100
; 3 %0011 <- D %1101
  and #$70
  eor #$ff
  adc #$68
@skip:  
  ora $82
  asl
  sta COLUPF

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...