On Wed, Aug 13, 2008 at 3:58 PM, Petter Urkedal <[EMAIL PROTECTED]> wrote:
> On 2008-08-01, Timothy Normand Miller wrote:
>> Here's what the access target looks like now:
>>
>> parameter TARGET_CFG=0;
>> parameter TARGET_ENG=1;
>> parameter TARGET_MEM=2;
>> parameter TARGET_VMEM=3;
>> parameter TARGET_IO=4;
>> parameter TARGET_PROM=5;
>>
>> access_target[4:1] is pushed into the command fifo, so flags[2] refers
>> to VGA memory (A0000 to BFFFF), and flags[3] is I/O space. That
>> target won't be understood by the S3, so we have to convert the
>> accesses to MEM accesses, and it's HQ's responsibility to add an
>> offset to the address.
>
> If I understand this correctly, flags = 2^(target - 1) where target is
> one of {TARGET_ENG, TARGET_MEM, TARGET_VMEM, TARGET_IO}? About the
> translation, is the following correct?
Actually, it's {TARGET_IO, TARGET_VMEM, TARGET_MEM, TARGET_ENG}.
>
> TARGET_ENG -- MEM_SEND_ADDR_ENG without offset
> TARGET_MEM -- MEM_SEND_ADDR_MEM without offset
> TARGET_VMEM -- MEM_SEND_ADDR_MEM with offset 0xa0000
There's nothing here about offsets. ENG and MEM indicate that an
address corresponding to one of those PCI BARs has been accessed.
VMEM indicates that the legacy VGA memory space has been accessed.
Also, the address we get is the whole PCI address. The upper bits
that include the address space that these are mapped into is included.
We really need to fix that in pci_address_decode!
At the moment, I'm working on making pci_address_decode handle VMEM
properly and also allow the local memory cache to be disabled.
> TARGET_IO -- HQ internal
And here, no matter what, you'll get the raw address that was on the
bus. I think these are byte addresses, but we need to pay attention
to the byte enables.
>
> Assuming it is, I made the following sketch of the poll_pci() function
> (the stub from your original "VGA text mode C version" post). That
> should nail down any misunderstanding I have about the bus protocol.
>
> void poll_pci()
> {
> while (read_io(PCI_T_CMD_COUNT)) {
> uint32_t addr, info, target;
>
> /* Get the target and address */
> info = read_io(PCI_T_CMD_INFO);
> assert((info & PCI_TCINFO_TYPE_MASK) == PCI_TCINFO_TYPE_ADDR);
> target = info & 15;
> addr = read_io(PCI_T_CMD_DATA);
Yeah, and that last read_io pops the queue entry.
>
> switch (target) {
> case 1: /* engine */
> write_io(MEM_SEND_ADDR_ENG, addr);
> break;
> case 2: /* memory */
> write_io(MEM_SEND_ADDR_MEM, addr);
> break;
> case 4: /* video memory */
> write_io(MEM_SEND_ADDR_MEM, addr + 0xa0000);
Well, we should in fact have a programmable offset, now that you
mention it. The offset isn't necessarily 0xa0000. That's just the
address of the space as seen by the host. In fact, the offset for
80x25 text mode may just be zero, and the pixel buffer that is scanned
to the monitor lived at some offset.
> break;
> case 8: /* IO */
> handle_io(addr); /* TODO */
> return;
> }
>
> while (read_io(PCI_T_CMD_COUNT) == 0);
This may be too synchronous. This could be prepared to get one
command in isolation, process it, and quit. A command is only one
entry. What we think of as reads are handled as two separate commands
that can be handled separately. If all you got was an address
command, and nothing else, you could just handle it and quit. In
reality, that's always followed by one read count or one or more write
words.
The thing is, PCI is relatively slow. It's possible that you could
catch just an address command then find nothing, because the write
word is coming up, but there's delay. Knowing what sorts of patterns
there are, it may be good to just sit around and wait. But you have
to be prepared to get write words in isolation, because you're getting
a burst but there are wait states. That is, on entry to this
function, the command could be write-word.
You could look at the word info and decide what to do based on what it
is. It is an address, a read count, or write data. What you need is
a loop that checks for entries, and if there is one, looks at the info
and pops it, then processes that command word in isolation, then
checks again for another one, etc. If some info must be held over
from one command to another, store it in a global variable.
For addresses, just forward info and store stuff in globals if you need to.
For write words, just forward them.
For reads, only then do you need to sit around in a loop waiting. Get
the read count, forward it on, then wait around for the response data
and forward it back.
> info = read_io(PCI_T_CMD_INFO);
> switch ((info & PCI_TCINFO_TYPE_MASK)) {
> case PCI_TCINFO_TYPE_WDATA:
> for (;;) {
> uint32_t data = read_io(PCI_T_CMD_DATA);
> uint32_t enables = info & 15;
> write_io(MEM_SEND_DATA_0000 + enables, data);
> if (!read_io(PCI_T_CMD_COUNT))
> /* CHECKME: Is it possible to know if we should have
> * waited for more data? */
No, it's not possible. You'll just stop getting write commands.
Basically, if the command queue is empty, consider it safe to quit.
Just be prepared to continue where you left off.
> break;
> info = read_io(PCI_T_CMD_INFO);
> }
> break;
> case PCI_TCINFO_TYPE_RCOUNT: {
> uint32_t count, data;
> count = read_io(PCI_T_CMD_DATA);
> write_io(MEM_SEND_READ_COUNT, count);
> while (count) {
> while (!read_io(MEM_READQ_AVAIL));
> data = read_io(MEM_READQ_DATA);
> write_io(PCI_TR_DATA, data);
decrement count
> }
> break;
> }
> default:
> assert(!"The sky is pink.");
> }
> }
> }
You have the right idea. Also, another thing we might want to look at
is some unrolled loops. For instance, with returning read data, you
could get the count and jump into the middle of a run of move
instructions. So if there are 16 read words available (should we fix
the fifos), fall into the top. If there are 15, jump over the first.
If there are 8, jump over the first 8. We should see if there's any
benefit to this before doing it. These are performance tweaks we
shouldn't do prematurely.
--
Timothy Normand Miller
http://www.cse.ohio-state.edu/~millerti
Open Graphics Project
_______________________________________________
Open-graphics mailing list
[email protected]
http://lists.duskglow.com/mailman/listinfo/open-graphics
List service provided by Duskglow Consulting, LLC (www.duskglow.com)