On Thu, Jul 31, 2008 at 5:01 PM, Petter Urkedal <[EMAIL PROTECTED]> wrote:
> On 2008-07-30, Timothy Normand Miller wrote:
>> > I don't think we can. val_or_addr comes directly from res_o of the ALU,
>> > which by the way already is MUXed after registration.
>>
>> Ok, then we'll just have to see how it goes. We'll wire it up and try it.
>
> I submitted a revision which assumed the port read data is passed
> combinatorially back to HQ. You can find a matching but rather sketchy
> bridge wrapper on
> http://www.eideticdew.org/~urkedal/ogp/xp10_bridge_wrapper.v.
> It has a number of TODOs, CHECKMEs, and FIXMEs. In particular, I
> didn't find a signal from PCI which indicates the target of the command,
> and I wasn't sure how to indicate memory vs engine addresses to the
> bridge.
This is great stuff! My comments marked with ##
always @(
hqio_addr or br2hq_cmd_free or br2hq_read_count or br2hq_read_data or
pci2hq_cmd_valid or pci2hq_cmd_type or pci2hq_cmd_flags or pci2hq_cmd_data
) begin
case (hqio_addr)
/* TODO
PCI_M_CMD_FREE: hqio_inport =
PCI_MW_FREE: hqio_inport =
PCI_MR_COUNT: hqio_inport =
PCI_MR_DATA: hqio_inport =
PCI_TW_COUNT: hqio_inport = // Redundant due to PCI_TW_DATA?
## PCI_TW_COUNT would be wired to pci2hq_cmd_count
## There are two counts that we need to deal with. One is the number
of entries in the command queue that can be popped. That needs its
own port. The other is a number that indicates the number of read
words are being requested when a PCI read is pending. In the latter
case, two entries will be pushed into the queue. The first entry is
of type 1, and the address comes in the TW_DATA port. The second
entry is of type 2, which is the read word count, and that also
appears in TW_DATA.
*/
PCI_TW_INFO:
/* FIXME: Target number goes into the top 3 bits. */
hqio_inport = {32{pci2hq_cmd_valid}}
& {pci2hq_cmd_type, 20'b0, pci2hq_cmd_flags};
## I'm not sure it's necessary to mask this. When the data isn't
valid, it's okay to have garbage on the port, and popping will have no
effect. Of course, if a pop occurs blindly at the wrong time, we
might pop something, or we might not, depending on what's being pushed
in. The correct way to access this is to check how many words are in
the queue (from TW_COUNT), and then pop that many or fewer from
TW_DATA. If you do that, then what appears in both TW_INFO and
TW_DATA is guaranteed to be valid.
PCI_TW_DATA: hqio_inport = pci2hq_cmd_data;
//PCI_TR_PENDING: hqio_inport = // Redundant?
## I think it is. If for whatever reason the microprogram lost a read
request, then we're kinda screwed anyhow. The rule is that if HQ pops
something from this queue, it better be ready to handle it properly.
If not, then the request sits safely in the queue.
MEM_CMDQ_FREE: hqio_inport = br2hq_cmd_free;
MEM_READQ_AVAIL:hqio_inport = br2hq_read_count;
MEM_READQ_DATA: hqio_inport = br2hq_read_data;
default: hqio_inport = 0;
endcase
end
always @(posedge clock) begin
hq2br_cmd_data <= hqio_outport;
hq2br_cmd_type <= BR_CMD_IDLE;
// CHECKME: Assuming flags are ignored for BR_CMD_ADDR and BR_CMD_RCOUNT:
hq2br_cmd_flags <= hqio_addr & 15;
Since there are only four flags bits, the & 15 isn't necessary.
Besides, we would use [3:0] instead so that a stupid synthesizer
didn't generate any logic here. You can add [3:0] for documentation
purposes.
hq2br_cmd_enq <= 0;
hq2br_deq_read <= 0;
hq2pci_cmd_deq <= 0;
hq2pci_read_enq <= 0;
hq2pci_read_data <= hqio_outport;
// Assign dequeue signals if port read.
if (hqio_enable_in)
case (hqio_addr)
MEM_READQ_DATA:
hq2br_deq_read <= 1;
PCI_TW_DATA, PCI_TR_ADDR:
## Looks like these are really the same register. They both get data
from exactly the same place and dequeue in the same way. Perhaps it
should be called PCI_CMD_DATA or something that fits with the scheme.
Write address, read address, write data, and read count all come from
the same bits of the same queue.
hq2pci_cmd_deq <= 1;
endcase
// Assign enqueue and command type if port write.
if (hqio_enable_out) begin
if (MEM_SEND_DATA_0000 <= hqio_addr
&& hqio_addr < MEM_SEND_DATA_0000 + 16) begin
## if (hqio_addr[8:4] == (MEM_SEND_DATA_0000>>4))
## This does the same thing and may result in less logic if the
synthesizer is stupid. Since MEM_SEND_DATA is a constant, we probably
can't do a part select on it, but a constant shifted by a constant
will resolve to a constant, so this is just a compare.
hq2br_cmd_enq <= 1;
hq2br_cmd_type <= BR_CMD_WRITE;
end
case (hqio_addr)
PCI_TR_DATA:
hq2pci_read_enq <= 1;
MEM_SEND_ADDR_MEM: begin
hq2br_cmd_enq <= 1;
hq2br_cmd_type <= BR_CMD_ADDR;
// FIXME: Where do we indicate memory vs engine?
## In bypass mode, this comes from pci2hq_cmd_type alongside the
address. To send the data out, we set hq2br_cmd_flags here to a
constant value of 4'b0010.
end
MEM_SEND_ADDR_ENG: begin
hq2br_cmd_enq <= 1;
hq2br_cmd_type <= BR_CMD_ADDR;
// FIXME: Where do we indicate memory vs engine?
## Here, we set hq2br_cmd_flags to 4'b0001.
end
MEM_SEND_READ_COUNT: begin
hq2br_cmd_enq <= 1;
hq2br_cmd_type <= BR_CMD_RCOUNT;
end
endcase
end
end
## Ok, looks good. Now, we need the bypass mode. With HQ in place,
we kinda have to have a register stage between the fifos. There are
some shortcuts and cautions, however:
## For read data, there will never be more than 16 words requested, so
there's no need to check to make sure we can dump from br2hq_read into
hq2pci_read. If there's a valid word from the bridge, we can just pop
it and dump it into the PCI read data queue.
## On the other hand, the command queue from PCI to the bridge CAN
fill, although (when PCI is in control), only when we're doing long
bursts of writes. I'm doing this off the top of my head, so I might
screw it up:
// Some of your stuff
wire [31:0] hq2br_cmd_data;
wire [1:0] hq2br_cmd_type;
wire [3:0] hq2br_cmd_flags;
// This is the enqueue and also indicates back to us that we're
holding something.
reg hq2br_cmd_enq;
// Only dequeue from PCI if either we're not holding anything, or what
we may or may not have been holding can go into the bridge queue.
// This signal means we CAN dequeue. Whether or not we did also
depends on whether or not valid is true. We don't have to combine
// those signals in any way to make this work.
// Note: We need to connect up the FULL signal on the hq2br queue and
bring it in here for this.
assign hq2pci_cmd_deq = !hq2br_cmd_enq || !hq2br_cmd_full;
always @(posedge clock) begin
// Only clear the enq if the queue doesn't say it's full. As long
as the queue is full, it ignores enq, so you have to hold it on.
if (!hq2br_cmd_full) hq2br_cmd_enq <= 0;
...
if (bypass_mode) begin
// Grab some data and store it (even if it's not valid)
if (hq2pci_cmd_deq) begin
hq2br_cmd_data <= pci2hq_cmd_data;
hq2br_cmd_type <= pci2hq_cmd_type;
hq2br_cmd_flags <= pci2hq_cmd_flags;
end
hq2br_cmd_enq <= pci2hq_cmd_valid;
end
...
end
--
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)