Jump to content
IGNORED

Reading a byte from VRAM?


Mike Harris

Recommended Posts

All this time I have been writing to VRAM making all of these beautiful patterns and graphics but for the life of me I can't read a single byte of data from VRAM


Say VRAM Start is at 1800h or VRAM: EQU 1800h

 

So I decide to put a line at the top of the screen and for giggles the data looks like this.

 

DB 38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38

How would I read that the number 38 is at any one of those addresses?

 

If I were to reason it out I would say that VRAM+12 would be 32 or in this case

 

DB 38,38,38,38,38,38,38,38,38,38,38,16,16,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38

 

VRAM+12 would equal 16

At present I have been stumped for two days just trying to read a single byte of data from a VRAM memory location and I have tried BIOS Calls and have come up with zilch.

 

Any help would be greatly appreciated

BTW, everything is in Z80 Assembly.

Edited by Mike Harris
Link to comment
Share on other sites

ColecoVision reads VRAM using port 0xBE for Read Data (to make sure my terminology isn't off, you are writing data using port 0xBE as well). Reading from it after setting the address (using port 0xBF) should work.

 

The only gotcha is that when you set the VDP address, there's a bit which controls whether the VDP does a prefetch. If the address bit >4000 is set, the VDP will NOT prefetch - this is the value you're adding to write data. Simply clear that bit for reads.

 

Also, make sure you have a suitable delay between setting the address and reading the data port. It can take the VDP up to 8 microseconds to actually fetch that byte, and the Z80 can turn it around faster than that.

 

(If you're using libraries or the BIOS, apologies, I've only done it at the low level.)

Link to comment
Share on other sites

lets say vram adr you want to read is in HL

the byte read will be in A.

 

ld hl,$1800

call rdadr

call rdbyte

st: jp st

 

rdadr:

push af

ld a,l
out ($BF),a
ld a,h
out ($BF),a

pop af

ret

 

rdbyte:

in a,($BE)

ret

 

if you are using interrupt, make sure a interrupt will not happend in the middle of the code.

  • Like 1
Link to comment
Share on other sites

Thank you for all the help thus far.

Tony from Electronic Adventures helped me out with a call and read from the data port and it worked out great.

I did learn a lot from the code you put up and I am so appreciative because everything you guys pass along helps me down the road.

Up until now I may have build a 40 room world but it is still based off basic fundamentals.
My next game is definitely going to be more complicated and needs some of these more advanced routines.

Edited by Mike Harris
Link to comment
Share on other sites

The original intent was to walk around and use the check to see if I am bumping into a wall.

Now my biggest issue is trying to calculate my SPRITE location and the pattern next to or underneath it on a grid of 768 locations.

Another gentleman showed me a formula but it is in C where I am writing in Z80 Assembly.

I guess these early days take the longest because you are trying to learn the land.
Once I have the pieces then I can actually build a working model.

So if anyone wants to share the Z80 code that tells you where your sprite is on the play screen that would help me greatly over another hurdle.
The rest is just gravy on the mash potatoes of building mazes and then filling them with players and treasures.

Link to comment
Share on other sites

Thank you for all the help thus far.

 

Tony from Electronic Adventures helped me out with a call and read from the data port and it worked out great.

 

I did learn a lot from the code you put up and I am so appreciative because everything you guys pass along helps me down the road.

 

Up until now I may have build a 40 room world but it is still based off basic fundamentals.

My next game is definitely going to be more complicated and needs some of these more advanced routines.

You mean Electric Adventures :) yes he knows and he is always helping :) and this guy have very long history coding z80 and also at the VDP :) I think he started coding in 1983.

Link to comment
Share on other sites

ColecoVision reads VRAM using port 0xBE for Read Data (to make sure my terminology isn't off, you are writing data using port 0xBE as well). Reading from it after setting the address (using port 0xBF) should work.

 

The only gotcha is that when you set the VDP address, there's a bit which controls whether the VDP does a prefetch. If the address bit >4000 is set, the VDP will NOT prefetch - this is the value you're adding to write data. Simply clear that bit for reads.

 

Also, make sure you have a suitable delay between setting the address and reading the data port. It can take the VDP up to 8 microseconds to actually fetch that byte, and the Z80 can turn it around faster than that.

 

(If you're using libraries or the BIOS, apologies, I've only done it at the low level.)

 

It takes 8ms, and you have to mask the NMI too? I bet the lookup could be done in RAM/ROM at least as quickly, and without having to worry about the video chip's interrupt.

 

This is why I encourage people to make the VDC an out-only system as much as possible.

Link to comment
Share on other sites

 

It takes 8ms, and you have to mask the NMI too? I bet the lookup could be done in RAM/ROM at least as quickly, and without having to worry about the video chip's interrupt.

 

This is why I encourage people to make the VDC an out-only system as much as possible.

 

ms usually means milliseconds, us (though technically the wrong character) is closer for microseconds.

 

But yes. If an NMI occurs, the NMI routine usually clears the VDP status word and performs VDP work. If the NMI routine changes the address on the VDP between any of your own steps, there's no notification to your code and you'll access the wrong address. This can happen on writes as well as reads, so you need to program defensively - either ensure you can not be interrupted (whether by disabling interrupts on the VDP (an act which itself can be interrupted!) or controlling your timing (such as doing it immediately after NMI has already occurred)), or ensure the NMI can't change the VDP address on you.

Link to comment
Share on other sites

Well, what I could have done to avoid accessing VRAM would be to have my maps 768 bytes long zero's and everything and traverse that as an array but then I would be stuck with a very large rom.

Considering I have a minimum of 40 rooms of what is basically one half the screen mirrored then that would just be wasteful.

 

So, I have everything working so far just by disabling NMI before any reads or writes and I can optimize once I get to the end of the road.

But for now I need an assembly routine that will tell me the pattern location underneath my Sprite so I can do a check to make sure I can not go through a wall.

I have tried several formulas that I found in C and what was given me by generous helpers.

 

Something to the effect of VRAM_NAME + X+Y*32 where VRAM_NAME is based at $1800

I have tried everything and just get garbage numbers.

Does anyone have an idea?

This is the last roadblock that is keeping me from building the rest of my world.

Link to comment
Share on other sites

You could unpack a wall map into RAM. If you represent a map position with 1 bit for "blocked" or "not", your 768-byte map can be represented in 128 bytes. Granted that's 1/8 of the total RAM available, but at least it's in the realm of possibility. Anyway, a quick'n'dirty function can find the appropriate bit and return a "blocked" or "not" indication.

 

Option 2 requires knowing the compression algorithm. If you know that much, you can write an access function that uses the known compression amounts to count its way through the map until it finds the value it wants, then return the data at that location. Both your navigation function and your drawing function can use this same function as a basis for determining if a wall exists. If you're using RLE, then it's probably not too difficult to figure out how it works. For that matter, maybe the source code for your library exists somewhere and spells it out.

Link to comment
Share on other sites

You could unpack a wall map into RAM. If you represent a map position with 1 bit for "blocked" or "not", your 768-byte map can be represented in 128 bytes. Granted that's 1/8 of the total RAM available, but at least it's in the realm of possibility. Anyway, a quick'n'dirty function can find the appropriate bit and return a "blocked" or "not" indication.

 

Option 2 requires knowing the compression algorithm. If you know that much, you can write an access function that uses the known compression amounts to count its way through the map until it finds the value it wants, then return the data at that location. Both your navigation function and your drawing function can use this same function as a basis for determining if a wall exists. If you're using RLE, then it's probably not too difficult to figure out how it works. For that matter, maybe the source code for your library exists somewhere and spells it out.

 

 

Awesome idea but I would have to change all of my code at this point when I know that the Sprite position algorithm written in Z80 is out there and I am hoping that one of my good buddy's will post it.

 

In the mean time I am trying to tune my own to see if I can get it to work.

 

It exists in C but is harder to come by online because everyone decided to start using C to program the Coleco due to the tools are more abundant and C is easier to work with. Z80 unto itself is fairly easy for me and I am not a fan of the C IDE. Accessing the Colecovision environment is where the challenge is.

Edited by Mike Harris
Link to comment
Share on other sites

But for now I need an assembly routine that will tell me the pattern location underneath my Sprite so I can do a check to make sure I can not go through a wall.

 

I can't help with Z80 assembly, but the posted math looks wrong. You basically need to convert a sprite pixel location to an 8x8 character position. Further complicating the issue slightly, Y coordinates start at -1 at the top instead of 0.

 

For the basic approach, you just want ((y+1)/8)*32+(x/8). But you may find that unsatisfactory depending on your sprites and your actual desire - that maps the top left pixel of the sprite to the character offset it's overlapping. (Offset because you still add the address of the screen image table).

 

You may want to offset the point of the sprite that you care about to the center by adding 4 to each the X and the Y before doing the above math (if you are doing 8x8 sprites). Alternately, or in conjunction with, you might want to check several points.

 

A good way to visualize what it looks like is to do the calculation, and place a character at that point, then just move the sprite around so you can get an idea where it's checking.

Link to comment
Share on other sites

Thank you for that.

My starting point is in a wide open blank area so in whatever direction I am looking ahead to the block I am moving to and pretty much if that block is occupied I will not proceed.
So any offsets I will toy with once I finish the game but I get what you are saying.

So far I have had a lot of great input from many of you with each a slightly different take on the math.
Even the Coleco BIOS math seems to be off but I will get there one way or another.

Link to comment
Share on other sites

I now have working walls.

I want everyone to know that I had help in these early days of getting over hurdles from Tony over at Electric Adventures.

 

He inspired me to get off my lazy rear end and make a game.

 

I mused over his shell that is online and learned how it all worked, the ports, the ins and outs.

Now he just helped me with the last part which was to define walls in assembly inside an open world.

So, I am going to get cracking but I really wanted him to get some credit because I was stumped with a one little SRL statement that made everything work.

  • Like 1
Link to comment
Share on other sites

Well, what I could have done to avoid accessing VRAM would be to have my maps 768 bytes long zero's and everything and traverse that as an array but then I would be stuck with a very large rom.

 

Considering I have a minimum of 40 rooms of what is basically one half the screen mirrored then that would just be wasteful.

 

So, I have everything working so far just by disabling NMI before any reads or writes and I can optimize once I get to the end of the road.

 

But for now I need an assembly routine that will tell me the pattern location underneath my Sprite so I can do a check to make sure I can not go through a wall.

 

I have tried several formulas that I found in C and what was given me by generous helpers.

 

Something to the effect of VRAM_NAME + X+Y*32 where VRAM_NAME is based at $1800

 

I have tried everything and just get garbage numbers.

 

Does anyone have an idea?

 

This is the last roadblock that is keeping me from building the rest of my world.

Z80 cant multiply or division, so its the funny part the good thing you want to multiply with a good binary number :) (32)

if we assume Y is stored in HL and X in DE. you can do like this:

IF you are using only bytes, you can zero H and D and put the values in L and E.

LD H,0

LD L,16 ;this is the Y Value

LD D,0

LD E,12 ;this is the X Value

ADD HL,HL

ADD HL,HL

ADD HL,HL

ADD HL,HL

ADD HL,HL ;Add HL to itself 5 times = HL x 32

ADD HL,DE ;Add DE to HL, so we add the X value

LD DE,$1800;Set BASE $1800

ADD HL,DE ;Add the BASE

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...