VRAM write macro $3FFF mask

Ask anything your want about Megadrive/Genesis programming.

Moderator: BigEvilCorporation

Post Reply
Okie
Interested
Posts: 37
Joined: Wed Jun 30, 2021 7:31 pm
Location: United States Of America

VRAM write macro $3FFF mask

Post by Okie » Sun Jul 11, 2021 9:22 pm

How come the VRAM Write Macro masks $3fff with the address?

*
move.l #(vdp_cmd_vram_write)|((\addr)&$3FFF)<<16|(\addr)>>14, vdp_control

Say we are using the Plane A Name Table Address. So it must be divisible by $2000

EXAMPLE1: RESULT IN $0000

Address = $C000

When we BITWISE AND them:

$3FFF = 0011 1111 1111 1111
$C000 = 1100 0000 0000 0000
$0000 = 0000 0000 0000 0000

EXAMPLE2: RESULT IN $2000

Address = $E000

When we BITWISE AND them:

$3FFF = 0011 1111 1111 1111
$E000 = 1110 0000 0000 0000
$2000 = 0010 0000 0000 0000

For any valid Plane A Name Table Address (divisible by $2000), after AND with $3FFF, it will be either $0000 or $20000

Is the AND $3FFF to keep it divisible by $2000? Unsure if all VRAM writs must be divisible $2000. Seems weird to force a
different address to keep it valid? The programmer might not now it was changed.

Also why would you bit shift it 16 bits which will just make it all zeros?

The method below makes more sense to me.

*
add.l #vram_addr_plane_a, d1 ; Add VRAM address offset
lsl.l #0x2, d1 ; Shift bits 14/15 of address to bits 16/17
lsr.w #0x2, d1 ; Shift lower word back
swap d1 ; Swap address hi/lo
ori.l #vdp_cmd_vram_write, d1 ; OR in VRAM write command

* Source is from BigEvilCorporation

Thank You;
-Okie

TmEE co.(TM)
Very interested
Posts: 2440
Joined: Tue Dec 05, 2006 1:37 pm
Location: Estonia, Rapla City
Contact:

Re: VRAM write macro $3FFF mask

Post by TmEE co.(TM) » Mon Jul 12, 2021 4:03 am

This stems from TMS99xx and SMS VDPs, which only had 16bit command words with 16KB VRAM. MD VDP extended the command words to 32bits and the new address bits (and few extra things) are in the second part, while first part is kept like the older stuff.
There's some playroom with how you arrange the bits depending on what exactly you want to do, some places may be optimizable when you have completely known access pattern but a generic solution that handles any address will have to do stuff you have already seen.
Mida sa loed ? Nagunii aru ei saa ;)
http://www.tmeeco.eu
Files of all broken links and images of mine are found here : http://www.tmeeco.eu/FileDen

flamewing
Very interested
Posts: 56
Joined: Tue Sep 23, 2014 2:39 pm
Location: France

Re: VRAM write macro $3FFF mask

Post by flamewing » Tue Jul 13, 2021 7:47 pm

Okie wrote:
Sun Jul 11, 2021 9:22 pm
move.l #(vdp_cmd_vram_write)|((\addr)&$3FFF)<<16|(\addr)>>14, vdp_control
Okie wrote:
Sun Jul 11, 2021 9:22 pm
add.l #vram_addr_plane_a, d1 ; Add VRAM address offset
lsl.l #0x2, d1 ; Shift bits 14/15 of address to bits 16/17
lsr.w #0x2, d1 ; Shift lower word back
swap d1 ; Swap address hi/lo
ori.l #vdp_cmd_vram_write, d1 ; OR in VRAM write command
Let me add some different comments to a slightly modified version of the latter code for more direct comparison:

Code: Select all

move.l  #\addr, d1                  ; Load address into d1
lsl.l   #0x2, d1                    ; High word of d1 is \addr>>14; low word of d1 is (\addr&$3FFF)<<2
lsr.w   #0x2, d1                    ; High word of d1 is \addr>>14; low word of d1 is \addr&$3FFF
swap    d1                          ; High word of d1 is \addr&$3FFF; low word of d1 is \addr>>14
ori.l   #vdp_cmd_vram_write, d1     ; OR in VRAM write command
move.l  d1, vdp_control             ; Write to VDP
That is, they do the same thing. The difference being that the first version does it in a single instruction, whereas the latter form needs a lot more instructions (24 bytes and 74 cycles for the latter versus 10 bytes and 28 cycles for the former).

Okie
Interested
Posts: 37
Joined: Wed Jun 30, 2021 7:31 pm
Location: United States Of America

Re: VRAM write macro $3FFF mask

Post by Okie » Tue Jul 20, 2021 2:37 pm

Thank you that explanation helped me out a lot. I am guessing the
assembler evaluates the expression during assemble time? Im guessing the
expressions vdp_cmd_vram_write)|((\addr)&$3FFF)<<16|(\addr)>>14 is handled by snasm
or another assembler as it is assembled?

I made notes to make sure I understood
it.

Vram Write Macro MASTER EXPLAIN

Explanation:

Using Address Write As A Long 32 Bits

Writes The Following To The VDP Control Port C00004, ready to accept data to the Data Port
The Command - That We Are Writing To VRAM ( Operation ) , which is 6 bits.
The Address - That We Are Writing To , which is 16 bits

Vram Write Command is 000001

The Pattern For Command / Address

HIGH 1st C0004 CD1 CD0 A13 A12 A11 A10 A9 A8 ( D15 ~ D8 )
A7 A6 A5 A4 A3 A2 A1 A0 ( D7 ~ D0 )

LOW 2nd C0004 0 0 0 0 0 0 0 0
CD5 CD4 CD3 CD2 0 0 A15 A14

1-Because the bits of the Command is jumbled around it needs to be a long when OR'd,
the variable for the commands are is 32 bit long and is a different value from the 6 bit command
for example a vdp_cmd_vram_write is
0100 0000 0000 0000 0000 0000 0000 0000
-- ----
the _ bits are the command bits shown in the pattern above

2 - We jumble around the address bits note


Set the VRAM (video RAM) address to write to next
SetVRAMWrite: macro addr
move.l #(vdp_cmd_vram_write)|((\addr)&$3FFF)<<16|(\addr)>>14, vdp_control
endm

Lets Break This Down..
Say Adress = 1111 1111 1100 1110


1. ((\addr)&$3FFF) << 16

Note (\addr)&$3FFF Is ITSELF IN ITS OWN PARENTHESIS BECUASE & OPERATOR IN SNASM HAS A LOWER PRIORITY
THAN << OR >>. So To Force \addr to and with $3fff and not addr & with ( $3fff < 16 )


(\addr)&$3FFF - (MASK) AND 0011 1111 1111 1111 with the address, resulting with all the bits the same
as the bit of the address EXCEPT the 14th and 15th bit which result in 00

1111 1111 1100 1110 addr
0011 1111 1111 1111 $3FFF
0011 1111 1100 1110

0011 1111 1100 1110 << 16 ( as long word ) = 0011 1111 1100 1110 0000 0000 0000 0000
-- ---- ---- ----

All the bits set for the Address of the HIGH WORD PORTION - Note The underline bits are the HIGH WORD ADRESS BITS


2. (\addr)>>14

1111 1111 1100 1110 >> 14


= 0000 0000 0000 0000 0000 0000 0000 0011
--

All the bits set for the Address of the LOW WORD PORTION - Note The underline bits are the LOW WORD ADRESS BITS


3. (vdp_cmd_vram_write) | (\addr)&$3FFF << 16 OR the VDP_CMD_VRAM_WRITE WITH THE HIGH WORD OF ADREESS

| has same precedence as & BTW. Because | has lower precedence than << or >> , it is performed after and the operations
that have the same precedence are performed left to right. So The two | are done left to right so this or is done first

0100 0000 0000 0000 0000 0000 0000 0000 vdp_cmd_vram_write
0011 1111 1100 1110 0000 0000 0000 0000 ((\addr)&$3FFF) << 16
0111 1111 1100 1110 0000 0000 0000 0000


4. finally OR THIS RESULT WITH THE LOW WORD OF THE ADRESS

0111 1111 1100 1110 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0011
0111 1111 1100 1110 0000 0000 0000 0011


WE MOVE THIS WHOLE EVALUTED EXPRESSION TO THE CONTROL PORT ( c0004 ) as a long word


All These expressions in the move expression are performed by assembler it appears so they dont add
more code. COME BACK AND SEE IF THIS IS TRUE

Post Reply