URL
https://opencores.org/ocsvn/xulalx25soc/xulalx25soc/trunk
Subversion Repositories xulalx25soc
Compare Revisions
- This comparison shows the changes necessary to convert path
/xulalx25soc/trunk/rtl
- from Rev 58 to Rev 59
- ↔ Reverse comparison
Rev 58 → Rev 59
/wbufifo.v
5,7 → 5,7
// Project: XuLA2 board |
// |
// Purpose: This was once a FIFO for a UART ... but now it works as a |
// synchronous FIFO for JTAG-wishbone conversion 36-bit codewords. |
// synchronous FIFO for JTAG-wishbone conversion 36-bit codewords. |
// |
// |
// Creator: Dan Gisselquist, Ph.D. |
45,6 → 45,18
reg [(BW-1):0] fifo[0:(FLEN-1)]; |
reg [(LGFLEN-1):0] r_first, r_last; |
|
reg will_overflow; |
initial will_overflow = 1'b0; |
always @(posedge i_clk) |
if (i_rst) |
will_overflow <= 1'b0; |
else if (i_rd) |
will_overflow <= (will_overflow)&&(i_wr); |
else if (i_wr) |
will_overflow <= (r_first+2 == r_last); |
else if (r_first+1 == r_last) |
will_overflow <= 1'b1; |
|
// Write |
initial r_first = 0; |
always @(posedge i_clk) |
52,7 → 64,7
r_first <= { (LGFLEN){1'b0} }; |
else if (i_wr) |
begin // Cowardly refuse to overflow |
if (r_first+1 != r_last) |
if ((i_rd)||(~will_overflow)) // (r_first+1 != r_last) |
r_first <= r_first+{{(LGFLEN-1){1'b0}},1'b1}; |
// else o_ovfl <= 1'b1; |
end |
60,7 → 72,6
if (i_wr) // Write our new value regardless--on overflow or not |
fifo[r_first] <= i_data; |
|
initial r_last = 0; |
// Reads |
// Following a read, the next sample will be available on the |
// next clock |
73,12 → 84,25
// 5 1 2 fifo[2] |
// 6 0 3 fifo[3] |
// 7 0 3 fifo[3] |
reg will_underflow; |
initial will_underflow = 1'b0; |
always @(posedge i_clk) |
if (i_rst) |
will_underflow <= 1'b0; |
else if (i_wr) |
will_underflow <= (will_underflow)&&(i_rd); |
else if (i_rd) |
will_underflow <= (r_last+1==r_first); |
else |
will_underflow <= (r_last == r_first); |
|
initial r_last = 0; |
always @(posedge i_clk) |
if (i_rst) |
r_last <= { (LGFLEN){1'b0} }; |
else if (i_rd) |
begin |
if (r_first != r_last) |
if ((i_wr)||(~will_underflow)) // (r_first != r_last) |
r_last <= r_last+{{(LGFLEN-1){1'b0}},1'b1}; |
// Last chases first |
// Need to be prepared for a possible two |
92,8 → 116,8
|
wire [(LGFLEN-1):0] nxt_first; |
assign nxt_first = r_first+{{(LGFLEN-1){1'b0}},1'b1}; |
assign o_err = ((i_wr)&&(nxt_first == r_last)) |
||((i_rd)&&(r_first == r_last)); |
assign o_err = ((i_wr)&&(will_overflow)&&(~i_rd)) |
||((i_rd)&&(will_underflow)&&(~i_wr)); |
|
// wire [(LGFLEN-1):0] fill; |
// assign fill = (r_first-r_last); |
/wbuexec.v
35,6 → 35,13
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
`define WB_IDLE 3'b000 |
`define WB_READ_REQUEST 3'b001 |
`define WB_WRITE_REQUEST 3'b010 |
`define WB_ACK 3'b011 |
`define WB_WAIT_ON_NEXT_WRITE 3'b100 |
`define WB_FLUSH_WRITE_REQUESTS 3'b101 |
|
module wbuexec(i_clk, i_rst, i_stb, i_codword, o_busy, |
o_wb_cyc, o_wb_stb, o_wb_we, o_wb_addr, o_wb_data, |
i_wb_ack, i_wb_stall, i_wb_err, i_wb_data, |
43,9 → 50,10
// The command inputs |
input i_stb; |
input [35:0] i_codword; |
output reg o_busy; |
output wire o_busy; |
// Wishbone outputs |
output reg o_wb_cyc, o_wb_stb, o_wb_we; |
output wire o_wb_cyc, o_wb_stb; |
output reg o_wb_we; |
output reg [31:0] o_wb_addr, o_wb_data; |
// Wishbone inputs |
input i_wb_ack, i_wb_stall, i_wb_err; |
65,180 → 73,226
wire [31:0] w_cod_data; |
assign w_cod_data={ i_codword[32:31], i_codword[29:0] }; |
assign w_new_err = ((w_accept) |
&&((i_codword[35:33] != 3'h3)||(~o_wb_we)) |
&&(i_codword[35:33] != 3'h3) |
&&(i_codword[35:30] != 6'h2e)); |
|
reg [2:0] wb_state; |
reg [9:0] r_acks_needed, r_len; |
reg r_inc, r_new_addr, last_read_request, last_ack, zero_acks; |
|
reg r_inc, r_wb_err, r_new_addr, r_eow; |
initial r_wb_err = 1'b0; |
initial r_new_addr = 1'b1; |
initial wb_state = `WB_IDLE; |
initial o_stb = 1'b0; |
always @(posedge i_clk) |
if (i_rst) |
begin |
wb_state <= `WB_IDLE; |
o_stb <= 1'b1; |
o_codword <= { 6'h3, 30'h000 }; |
r_wb_err <= 1'b0; |
o_wb_cyc <= 1'b0; |
end else if (o_wb_cyc) // In the middle of a bus transaction |
begin |
o_stb <= 1'b0; |
o_codword <= { 6'h3, i_wb_data[29:0] }; |
end else case(wb_state) |
`WB_IDLE: begin |
// Now output codewords while we're idle, |
// ... unless we get an address command (later). |
o_stb <= 1'b0; |
|
// Deal with bus errors |
if (r_wb_err) |
// The new instruction. The following |
// don't matter if we're not running, |
// so set them any time in this state, |
// and if we move then they'll still be |
// set right. |
// |
// Increment addresses? |
r_inc <= i_codword[30]; |
// Will this be a write? |
o_wb_we <= (~i_codword[35]); |
// |
// Our next codeword will be the new address (if there |
// is one). Set it here. The o_stb line will determine |
// if this codeword is actually sent out. |
// |
o_codword <= { 4'h2, o_wb_addr }; |
o_wb_we <= (i_codword[35:34] != 2'b11); |
// |
// The output data is a don't care, unless we are |
// starting a write. Hence, let's always set it as |
// though we were about to start a write. |
// |
o_wb_data <= w_cod_data; |
// |
if (i_stb) |
begin |
if (w_eow) |
o_wb_cyc <= 1'b0; |
o_wb_stb <= 1'b0; |
end else if ((i_wb_err)||(w_new_err)) |
begin |
o_wb_cyc <= (~o_busy); |
o_wb_stb <= 1'b0; |
r_wb_err <= 1'b1; |
// |
o_stb <= 1'b1; |
o_codword <= { 6'h5, 30'h0000 }; |
// |
end else if ((o_wb_stb)&&(~i_wb_stall)) |
// Deal with the strobe line |
// Default is not to send any codewords |
// Do we need to broadcast a new address? |
// r_new_addr <= 1'b0; |
// |
casez(i_codword[35:32]) |
4'b0000: begin // Set a new (arbitrary) address |
r_new_addr <= 1'b1; |
o_wb_addr <= i_codword[31:0]; |
end |
4'b001?: begin // Set a new relative address |
r_new_addr <= 1'b1; |
o_wb_addr <= o_wb_addr |
+ { i_codword[32:31], i_codword[29:0] }; |
end |
4'b01??: begin // Start a write transaction, |
// address is alrdy set |
r_new_addr <= 1'b1; |
wb_state <= `WB_WRITE_REQUEST; |
end |
4'b11??: begin // Start a vector read |
// Address is already set ... |
// This also depends upon the decoder working |
if (r_new_addr) |
o_stb <= 1'b1; |
wb_state <= `WB_READ_REQUEST; |
end |
default: |
; |
endcase |
end end |
`WB_READ_REQUEST: begin |
r_new_addr <= 1'b0; |
|
if (i_wb_err) |
wb_state <= `WB_IDLE; |
|
o_stb <= (i_wb_err)||(i_wb_ack); |
|
if (i_wb_err) |
o_codword <= { 6'h5, i_wb_data[29:0] }; |
else |
o_codword <= { 3'h7, i_wb_data[31:30], r_inc, |
i_wb_data[29:0] }; |
|
if ((r_inc)&&(~i_wb_stall)) |
o_wb_addr <= o_wb_addr + 32'h001; |
|
|
if (~i_wb_stall) // Deal with the strobe line |
begin // Strobe was accepted, busy should be '1' here |
if (r_len != 0) // read |
r_len <= r_len - 10'h01; |
else |
o_wb_stb <= 1'b0; |
if (last_read_request) // (r_len != 0) // read |
wb_state <= `WB_ACK; |
end end |
`WB_WRITE_REQUEST: begin |
r_new_addr <= 1'b0; |
|
if (o_wb_we) |
begin // Acknowledge a write |
o_stb <= 1'b1; |
o_codword <= { 6'h2, 30'h0000 }; |
end |
if (i_wb_err) |
o_codword <= { 6'h5, i_wb_data[29:0] }; |
else |
o_codword <= { 6'h2, i_wb_data[29:0] }; |
|
if (r_inc) |
o_wb_addr <= o_wb_addr + 32'h001; |
end else if (w_newwr) begin |
r_inc <= i_codword[30]; |
o_wb_data <= w_cod_data; |
o_wb_stb <= 1'b1; |
/* |
end else if (w_newrd) |
begin // This seems good, but it would stall the bus |
// BUS ERROR! |
o_wb_cyc <= 1'b0; |
o_stb <= 1'b1; |
o_codword <= { 4'h5, 32'h0000 }; |
*/ |
end |
if ((r_inc)&&(~i_wb_stall)) |
o_wb_addr <= o_wb_addr + 32'h001; |
|
if (w_eow) |
r_eow <= 1'b1; |
o_stb <= (i_wb_err)||(~i_wb_stall); |
|
if ((r_wb_err)||(i_wb_err)||(w_new_err)) |
// On an error, flush any inputs ... |
o_busy <= 1'b0; |
else if ((w_eow)||(w_newwr)||(r_eow)) |
// On a new command, we're busy again |
o_busy <= 1'b1; |
else if((o_wb_we)&&(o_wb_stb)&&(~i_wb_stall)&&(r_len==0)) |
// Once our command completes, if it was a write |
// command, then |
o_busy <= 1'b0; |
else if ((o_wb_we)&&(~o_wb_stb)) |
o_busy <= 1'b0; |
// Don't need to worry about accepting anything new |
// here, since we'll always be busy while in this state. |
// Hence, we cannot accept new write requests. |
// |
|
if (i_wb_err) |
begin |
wb_state <= `WB_FLUSH_WRITE_REQUESTS; |
// |
end else if (~i_wb_stall) |
wb_state <= `WB_WAIT_ON_NEXT_WRITE; |
end |
`WB_ACK: begin |
r_new_addr <= 1'b0; |
// |
// Now let's process the acknowledgements |
// No strobes are being sent out. No further |
// bus transactions are requested. We only need |
// to finish processing the last one(s) by waiting |
// for (and recording?) their acks. |
// |
if ((r_wb_err)||(i_wb_err)) |
begin |
// Acks are irrelevant here |
end else if (r_acks_needed != 10'h00) |
begin |
if ((i_wb_ack)&&(~o_wb_we)) |
begin // Return a read result |
o_stb <= 1'b1; |
o_codword <= { 3'h7, i_wb_data[31:30], r_inc, |
// Process acknowledgements |
if (i_wb_err) |
o_codword <= { 6'h5, i_wb_data[29:0] }; |
else |
o_codword <= { 3'h7, i_wb_data[31:30], r_inc, |
i_wb_data[29:0] }; |
end |
|
if ((i_wb_ack)&&(~w_newwr)) |
r_acks_needed <= r_acks_needed - 10'h001; |
else if ((~i_wb_ack)&&(w_newwr)) |
r_acks_needed <= r_acks_needed + 10'h001; |
end else if (r_acks_needed == 10'h0) |
begin |
if ((~o_wb_we)||(r_eow)||(w_eow)) // End our bus cycle |
o_wb_cyc <= 1'b0; |
else if (w_newwr) |
begin |
r_acks_needed <= r_acks_needed + 10'h001; |
o_wb_data <= w_cod_data; |
end |
// Return a read result, or (possibly) an error |
// notification |
o_stb <= (((i_wb_ack)&&(~o_wb_we)) || (i_wb_err)); |
|
if (((last_ack)&&(i_wb_ack))||(zero_acks)||(i_wb_err)) |
wb_state <= `WB_IDLE; |
end |
// |
// |
// |
// |
// |
end else if (i_stb) |
// |
// |
// |
// |
// |
begin |
// Default is not to send any codewords |
o_stb <= 1'b0; |
// Increment addresses? |
r_inc <= i_codword[30]; |
// Will this be a write? |
o_wb_we <= (~i_codword[35]); |
// Do we need to broadcast a new address? |
// r_new_addr <= 1'b0; |
// Errors are all clear by now |
r_wb_err <= 1'b0; |
// Need to be not-busy when o_wb_cyc is low |
o_busy <= 1'b0; |
// |
r_eow <= 1'b0; |
if (i_codword[35:32] == 4'h0) |
begin // Set a new address |
r_new_addr <= 1'b1; |
o_wb_addr <= i_codword[31:0]; |
end else if (i_codword[35:33] == 3'b001) |
begin // Set a new relative address |
o_wb_addr <= o_wb_addr |
+ { i_codword[32:31], i_codword[29:0] }; |
r_new_addr <= 1'b1; |
end else if (i_codword[35:34] == 2'b11) |
begin // Start a vector read |
// Address is already set ... |
// This also depends upon the decoder working |
r_len <= i_codword[9:0] - 10'h01; |
o_wb_cyc <= 1'b1; |
o_wb_stb <= 1'b1; |
r_acks_needed <= i_codword[9:0]; |
o_busy <= 1'b1; |
`WB_WAIT_ON_NEXT_WRITE: begin |
r_new_addr <= 1'b0; |
|
if (r_new_addr) |
begin |
o_stb <= 1'b1; |
o_codword <= { 4'h2, o_wb_addr }; |
r_new_addr <= 1'b0; |
end |
end else if (~i_codword[35]) |
begin // Start a write transaction, address is alrdy set |
o_wb_cyc <= 1'b1; |
o_wb_stb <= 1'b1; |
o_wb_data <= w_cod_data; |
o_busy <= 1'b1; |
r_len <= 10'h00; |
r_new_addr <= 1'b1; |
r_acks_needed <= 10'h01; |
o_codword <= { 6'h5, i_wb_data[29:0] }; |
o_stb <= (i_wb_err)||(w_new_err); |
|
o_wb_data <= w_cod_data; |
|
if (w_new_err) // Something other than a write or EOW |
wb_state <= `WB_IDLE; |
else if (i_wb_err) // Bus returns an error |
wb_state <= `WB_FLUSH_WRITE_REQUESTS; |
else if (w_newwr) // Need to make a new write request |
wb_state <= `WB_WRITE_REQUEST; |
else if (w_eow) // All done writing, wait for last ack |
wb_state <= `WB_ACK; |
end |
end else begin |
r_wb_err <= 1'b0; |
o_busy <= 1'b0; |
o_stb <= 1'b0; |
end |
`WB_FLUSH_WRITE_REQUESTS: begin |
// We come in here after an error within a write |
// We need to wait until the command cycle finishes |
// issuing all its write commands before we can go back |
// to idle. |
// |
// In the off chance that we are in here in error, or |
// out of sync, we'll transition to WB_IDLE and just |
// issue a second error token. |
r_new_addr <= 1'b0; |
|
o_codword <= { 6'h5, i_wb_data[29:0] }; |
o_stb <= (w_new_err); |
|
if ((w_eow)||(w_new_err)) |
wb_state <= `WB_IDLE; |
end |
default: begin |
o_stb <= 1'b1; |
o_codword <= { 6'h3, i_wb_data[29:0] }; |
wb_state <= `WB_IDLE; |
end |
endcase |
|
assign o_busy = (wb_state != `WB_IDLE) |
&&(wb_state != `WB_WAIT_ON_NEXT_WRITE) |
&&(wb_state != `WB_FLUSH_WRITE_REQUESTS); |
assign o_wb_cyc = (wb_state == `WB_READ_REQUEST) |
||(wb_state == `WB_WRITE_REQUEST) |
||(wb_state == `WB_ACK) |
||(wb_state == `WB_WAIT_ON_NEXT_WRITE); |
assign o_wb_stb = (wb_state == `WB_READ_REQUEST) |
||(wb_state == `WB_WRITE_REQUEST); |
|
always @(posedge i_clk) |
if (wb_state == `WB_IDLE) |
r_acks_needed <= 10'h00; // (i_codword[35])?i_codword[9:0]:10'h00; |
else if ((o_wb_stb)&&(~i_wb_stall)&&(~i_wb_ack)) |
r_acks_needed <= r_acks_needed + 10'h01; |
else if (((~o_wb_stb)||(i_wb_stall))&&(i_wb_ack)) |
r_acks_needed <= r_acks_needed - 10'h01; |
|
always @(posedge i_clk) |
last_ack <= (~o_wb_stb)&&(r_acks_needed == 10'h01); |
|
always @(posedge i_clk) |
zero_acks <= (~o_wb_stb)&&(r_acks_needed == 10'h00); |
|
always @(posedge i_clk) |
if ((wb_state == `WB_IDLE)&&(i_codword[35:34] == 2'b11)) |
r_len <= i_codword[9:0] - 10'h01; |
else if ((o_wb_stb)&&(~i_wb_stall)&&(|r_len)) |
r_len <= r_len - 10'h01; |
|
always @(posedge i_clk) |
last_read_request <= (r_len[9:0] == 10'h000); |
|
endmodule |