Forums

Sega Master System / Mark III / Game Gear
SG-1000 / SC-3000 / SF-7000 / OMV
Home - Forums - Games - Scans - Maps - Cheats - Credits
Music - Videos - Development - Hacks - Translations - Homebrew

View topic - Weird issue setting the palette

Reply to topic
Author Message
  • Joined: 12 Feb 2013
  • Posts: 80
Reply with quote
Weird issue setting the palette
Post Posted: Sat Oct 26, 2019 3:54 pm
I'm new to master system programming, but I encountered a strange issue with setting the palette.

To test, I prepared the palette as follows:
PALETTE:
ds.b $00 $01 $02 $03 $04 $05 $06 $07 $08 $09 $0A $0B $0C $0D $0E $0F
ds.b $10 $11 $12 $13 $14 $15 $16 $17 $18 $19 $1A $1B $1C $1D $1E $1F


My first thought was to set the palette ram this way:
ld hl, PALETTE
ld b, $20
ld c, Port_VDPData
otir


But the resulting palette came out wrong:
Quote
$00 $01 $02 $03 $05 $06 $07 $08 $0A $0B $0C $0D $0E $0F $11 $12
$13 $14 $16 $17 $18 $19 $1A $1C $1D $1E $1F $1F $1A $00 $00 $00


So I tried it this way so I could watch each palette entry get set in the debugger:
ld hl, PALETTE
ld b, $20
ld c, Port_VDPData
outi
ld a, b
jnz, -5


And to my surprise this way worked with the resulting palette correct:
Quote
$00 $01 $02 $03 $04 $05 $06 $07 $08 $09 $0A $0B $0C $0D $0E $0F
$10 $11 $12 $13 $14 $15 $16 $17 $18 $19 $1A $1B $1C $1D $1E $1F


So what is the difference in the 2 methods?
  View user's profile Send private message
  • Joined: 28 Sep 1999
  • Posts: 1197
Reply with quote
Post Posted: Sat Oct 26, 2019 4:51 pm
The first way should have worked fine, it's common to use OTIR in SMS games.

Maybe the problem comes from another place, like an interrupt could be triggered while you are loading the palette? Or perhaps the code that sets the CRAM write address has a problem? (that part wasn't included in your code)

If you are testing in an emulator I'd see if you get different results in another one. I'd also try removing parts of your program to make a simple test case to narrow down what the problem could be.
  View user's profile Send private message Visit poster's website
  • Joined: 08 Sep 2018
  • Posts: 270
Reply with quote
Post Posted: Sat Oct 26, 2019 4:58 pm
Maybe try loading it in 16 color chunks
dont forget to select your palette index first
also set your palette data up like this


PaletteData:
ds.b $00 $01 $02 $03 $04 $05 $06 $07 $08 $09 $0A $0B $0C $0D $0E $0F
PaletteDataEnd:

PaletteData_2:
ds.b $10 $11 $12 $13 $14 $15 $16 $17 $18 $19 $1A $1B $1C $1D $1E $1F
PaletteDataEnd_2:


then set VRAM write to the first palette address in CRAM


;where color palette 1 is at $c000 and color palette index 2 is at $c010
    ld hl,$c000    ;palette address 1
    ld a,h
    out ($bf),a
    ld a,l
    out ($bf),a


then load in palette.


    ld hl,PaletteData
    ld b,(PaletteDataEnd-PaletteData)
    ld c,$be
    otir


Also may help do disable interrupts prior to loading stuff into vram then re-enabling it when youre done.
  View user's profile Send private message
  • Joined: 12 Feb 2013
  • Posts: 80
Reply with quote
Post Posted: Sat Oct 26, 2019 6:00 pm
Thanks guys. Must be an interrupt. I can't think of any other reason.

The palette index is set properly with the command word.

Anyway, I'll keep the second version since it works. I just wanted to be sure there wasn't some quirk with the sms hardware I wasn't aware of.
  View user's profile Send private message
  • Joined: 01 Jan 2014
  • Posts: 331
Reply with quote
Post Posted: Sat Oct 26, 2019 10:47 pm
VDP can be in three possible states, vblank, active display or off (which is permanent vblank).

During active display your accesses to the VDP need to be padded by 26 cycles (its busy rending your screen). Failing to do so will result in corrupted data like you are seeing. You can get around this by writing during vblank or turning the screen off.

You can test this in Emulicious. In the master system options you will see the 'Enable VDP Constraints' option which you can toggle on and off.
  View user's profile Send private message
  • Joined: 12 Feb 2013
  • Posts: 80
Reply with quote
Post Posted: Sat Oct 26, 2019 11:17 pm
Yes, that is what I have read, but you can see the code above. It is virtually identical. Why would one have corruption and the other be fine?

And the corrupted values are always the same. So it's not random corruption. Weird.
  View user's profile Send private message
  • Joined: 01 Jan 2014
  • Posts: 331
Reply with quote
Post Posted: Sat Oct 26, 2019 11:30 pm
Its not identical though. otir means 21 cycles per write which is too short so corruption. The second routine is 30 cycles per write so you are safe.

In short you cannot use otir during active display.
  View user's profile Send private message
  • Joined: 12 Feb 2013
  • Posts: 80
Reply with quote
Post Posted: Sun Oct 27, 2019 1:16 am
Interesting. Thanks for the information. It is definitely in active display so that solves the mystery.

This code is close before it and sets active display on:
ld a, $E0
di
out (Port_VDPAddress), a
ld a, $81
out (Port_VDPAddress), a
ei


From what I can see in the code above:
the LSB is $E0 = 11100000
the MSB is $81 = 10000001

The MSB of the command word has the two C-bits at the top and here they are 10 so it is a VDP register write and the first bit being set means Register 1 is updated.

The LSB value is what the register gets so here it is 11100000 with the 7th bit D6 indicating Display visible. Since it is a 1, the display is active.

Whew, that was a weird condition for the corruption. Being new to the master system, I didn't know what was going on. Thanks for all the help everyone.
  View user's profile Send private message
  • Joined: 08 Sep 2018
  • Posts: 270
Reply with quote
Post Posted: Sun Oct 27, 2019 1:35 am
hey also btw it might help to have some kind of interrupt handler and status indicator that way when the VDP enters VBlank you can execute any copies/writes to VRAM or CRAM at the right time.
when you write to the VDP you should disable interrupts or turn off the VDP then turn it back on when you're done writing.

Be mindful of the amount of data you need to write to VRAM as well else itll take too long and cause issues. Typically I like to write my palette, map, tiles, sprites and SAT during a map init routine and then actively swap sprites or palettes and update the map if needed during the main loop since those objects are small relative to rewriting the entire screen and updating a whole tileset.
  View user's profile Send private message
  • Joined: 05 Sep 2013
  • Posts: 3763
  • Location: Stockholm, Sweden
Reply with quote
Post Posted: Sun Oct 27, 2019 9:21 pm
you're simply writing too fast with display on (and not during vblank).

you need at least 26 cycles between writes to do that properly, but you're using OTIR which takes just 21 cycles, so you're overwriting approximately 1 byte every 5 writes, and that's why using a slower loop it works fine

edit: OK I didn't see psidum already clarified that, sorry for repeating.
  View user's profile Send private message Visit poster's website
Reply to topic



Back to the top of this page

Back to SMS Power!