|
@@ -269,10 +269,7 @@ module abcbus (
|
|
|
//
|
|
|
// However, the rd and wr enable bits in the I/O map still apply.
|
|
|
//
|
|
|
- wire [7:0] abc_map_addr =
|
|
|
- abc_out_s[0] ? { 1'b1, iosel, 1'b0 } :
|
|
|
- abc_inp_s[0] ? { 1'b1, iosel, 1'b1 } :
|
|
|
- { 1'b0, abc_a_s[15:9] };
|
|
|
+ wire [7:0] abc_map_addr = { 1'b0, abc_a_s[15:9] };
|
|
|
wire [35:0] rdata_abcmemmap;
|
|
|
wire [35:0] abc_memmap_rd;
|
|
|
|
|
@@ -280,12 +277,7 @@ module abcbus (
|
|
|
// For I/O, don't allow the read/write enables to conflict with
|
|
|
// the direction of the I/O.
|
|
|
//
|
|
|
- wire [1:0] abcmap_masked_rdwr = cpu_wdata[31:30] &
|
|
|
- { ~cpu_addr[9] | ~cpu_addr[2],
|
|
|
- ~cpu_addr[9] | cpu_addr[2] };
|
|
|
-
|
|
|
- wire [8:0] next_dma_count = abc_dma_count - 1'b1;
|
|
|
- wire next_dma_empty = ~&next_dma_count;
|
|
|
+ wire [1:0] abcmap_masked_rdwr = cpu_wdata[31:30];
|
|
|
|
|
|
abcmapram abcmapram (
|
|
|
.aclr ( ~rst_n ),
|
|
@@ -293,92 +285,30 @@ module abcbus (
|
|
|
.clock ( sdram_clk ),
|
|
|
|
|
|
.address_a ( abc_map_addr ),
|
|
|
- .data_a ( { next_dma_count,
|
|
|
- abc_rden, abc_wren,
|
|
|
- abc_memaddr + 1'b1 } ),
|
|
|
- .wren_a ( abc_dma_update ),
|
|
|
- .byteena_a ( 4'b1111 ),
|
|
|
+ .data_a ( 36'bx ),
|
|
|
+ .wren_a ( 1'b0 ),
|
|
|
+ .byteena_a ( 4'bxxxx ),
|
|
|
.q_a ( abc_memmap_rd ),
|
|
|
|
|
|
.address_b ( cpu_addr[9:2] ),
|
|
|
- .data_b ( { cpu_wdata[8:0],
|
|
|
+ .data_b ( { 9'bx,
|
|
|
abcmap_masked_rdwr,
|
|
|
cpu_wdata[24:0] } ),
|
|
|
- .wren_b ( map_valid & ~cpu_addr[11] & cpu_wstrb[0] ),
|
|
|
- .byteena_b ( { cpu_addr[10],
|
|
|
- {3{~cpu_addr[10]}} } ),
|
|
|
+ .wren_b ( map_valid & cpu_wstrb[0] ),
|
|
|
+ .byteena_b ( 4'b1111 ),
|
|
|
|
|
|
.q_b ( rdata_abcmemmap )
|
|
|
);
|
|
|
|
|
|
- // Note: added one extra cycle of pipelining here for timing
|
|
|
- reg [24:0] abc_memaddr;
|
|
|
- reg [8:0] abc_dma_count;
|
|
|
- reg abc_dma_nzero;
|
|
|
- reg abc_rden;
|
|
|
- reg abc_wren;
|
|
|
+ assign cpu_rdata_map = { rdata_abcmemmap[26:25], 5'b0,
|
|
|
+ rdata_abcmemmap[24:0] };
|
|
|
|
|
|
- always @(negedge rst_n or posedge sdram_clk)
|
|
|
- if (~rst_n)
|
|
|
- begin
|
|
|
- abc_dma_count <= 9'b0;
|
|
|
- abc_dma_nzero <= 1'b0;
|
|
|
- abc_rden <= 1'b0;
|
|
|
- abc_wren <= 1'b0;
|
|
|
- abc_memaddr <= 26'b0;
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- { abc_dma_count, abc_rden, abc_wren, abc_memaddr } <= abc_memmap_rd;
|
|
|
- abc_dma_nzero <= |abc_memmap_rd[35:27]; // -> |abc_dma_count
|
|
|
- end
|
|
|
+ wire abc_rden = abc_memmap_rd[26];
|
|
|
+ wire abc_wren = abc_memmap_rd[25];
|
|
|
+ wire [24:0] abc_memaddr = abc_memmap_rd[24:0];
|
|
|
|
|
|
- //
|
|
|
- // RAM for the status register (INP 1). This is in a separate SRAM
|
|
|
- // so that it can be adjusted for certain DMA events.
|
|
|
- // bit [7:0] - status register value
|
|
|
- // bit [8] - clear bit 0 on read DMA empty
|
|
|
- // bit [9] - clear bit 0 on write DMA empty
|
|
|
- // bit [10] - clear bit 1 on write DMA empty
|
|
|
- // bit [11] - clear bit 7 on any DMA event
|
|
|
- //
|
|
|
- wire [15:0] status_out;
|
|
|
- wire [15:0] rdata_status;
|
|
|
-
|
|
|
- statusram statusram (
|
|
|
- .aclr ( ~rst_n ),
|
|
|
- .clock ( sdram_clk ),
|
|
|
-
|
|
|
- .address_a ( iosel ),
|
|
|
- .data_a ( status_out &
|
|
|
- ~{ 4'hf0, status_out[11], 5'b00000,
|
|
|
- status_out[10] & abc_out_s[0]
|
|
|
- & next_dma_empty,
|
|
|
- ((status_out[9] & abc_out_s[0]) |
|
|
|
- (status_out[8] & abc_inp_s[0]))
|
|
|
- & next_dma_empty } ),
|
|
|
- .wren_a ( abc_dma_update ),
|
|
|
- .q_a ( status_out ),
|
|
|
-
|
|
|
- .address_b ( cpu_addr[7:2] ),
|
|
|
- .data_b ( cpu_wdata[11:0] ),
|
|
|
- .q_b ( rdata_status ),
|
|
|
- .wren_b ( map_valid & cpu_addr[11] & cpu_wstrb[0] )
|
|
|
- );
|
|
|
-
|
|
|
- assign cpu_rdata_map = cpu_addr[11] ?
|
|
|
- { 16'b0, rdata_status } :
|
|
|
- cpu_addr[10] ?
|
|
|
- { 23'b0, rdata_abcmemmap[35:27] } :
|
|
|
- { rdata_abcmemmap[26:25], 5'b0,
|
|
|
- rdata_abcmemmap[24:0] };
|
|
|
-
|
|
|
- reg [24:4] abc_iobase;
|
|
|
reg abc_memrd_en;
|
|
|
reg abc_memwr_en;
|
|
|
- reg abc_dma_en;
|
|
|
- reg abc_iowr_en;
|
|
|
- reg abc_iord_en;
|
|
|
reg abc_do_memrd;
|
|
|
reg abc_do_memwr;
|
|
|
reg abc_racked;
|
|
@@ -393,16 +323,12 @@ module abcbus (
|
|
|
begin
|
|
|
abc_memrd_en <= 1'b0;
|
|
|
abc_memwr_en <= 1'b0;
|
|
|
- abc_dma_en <= 1'b0;
|
|
|
- abc_iord_en <= 1'b0;
|
|
|
- abc_iowr_en <= 1'b0;
|
|
|
abc_do_memrd <= 1'b0;
|
|
|
abc_do_memwr <= 1'b0;
|
|
|
sdram_rrq <= 1'b0;
|
|
|
sdram_wrq <= 1'b0;
|
|
|
abc_racked <= 1'b0;
|
|
|
abc_wacked <= 1'b0;
|
|
|
- abc_dma_update <= 1'b0;
|
|
|
end
|
|
|
else
|
|
|
begin
|
|
@@ -411,152 +337,202 @@ module abcbus (
|
|
|
// will have been stable for some time
|
|
|
abc_memwr_en <= abc_xmemwr;
|
|
|
abc_memrd_en <= abc_xmemrd;
|
|
|
- abc_dma_en <= iosel_en & (abc_out[0] | abc_inp[0]) & abc_stb[3] &
|
|
|
- abc_dma_nzero;
|
|
|
- abc_iowr_en <= iosel_en & |abc_out & abc_stb[3];
|
|
|
- abc_iord_en <= iosel_en & |abc_inp & abc_stb[3];
|
|
|
-
|
|
|
- abc_do_memrd <= abc_rden & (abc_memrd_en |
|
|
|
- (abc_iord_en & abc_inp[0]));
|
|
|
- abc_do_memwr <= abc_wren & (abc_memwr_en | abc_iowr_en);
|
|
|
+
|
|
|
+ abc_do_memrd <= abc_rden & abc_memrd_en;
|
|
|
+ abc_do_memwr <= abc_wren & abc_memwr_en;
|
|
|
abc_racked <= abc_do_memrd & (sdram_rack | abc_racked);
|
|
|
abc_wacked <= abc_do_memwr & (sdram_wack | abc_wacked);
|
|
|
|
|
|
sdram_rrq <= abc_do_memrd & ~abc_racked;
|
|
|
sdram_wrq <= abc_do_memwr & ~abc_wacked;
|
|
|
-
|
|
|
- // This will be true for one cycle only, which is what we want
|
|
|
- abc_dma_update <= abc_dma_en &
|
|
|
- ((sdram_rrq & abc_racked) |
|
|
|
- (sdram_wrq & abc_wacked));
|
|
|
end // else: !if(~rst_n)
|
|
|
|
|
|
- assign sdram_addr =
|
|
|
- (abc_dma_en & |abc_dma_count) ? abc_memaddr :
|
|
|
- (abc_iord_en|abc_iowr_en) ? { abc_iobase, |abc_inp_s, abc_a_s[2:0] } :
|
|
|
- { abc_memaddr[24:9], abc_a_s[8:0] };
|
|
|
-
|
|
|
+ assign sdram_addr = { abc_memaddr[24:9], abc_a_s[8:0] };
|
|
|
assign sdram_wd = abc_di;
|
|
|
+
|
|
|
+ // I/O data registers; RST# is considered OUT 7 even through
|
|
|
+ // it is an IN from the ABC point of view.
|
|
|
+ //
|
|
|
+ // OUT register, written from ABC: <addr 2:0> <data 7:0>
|
|
|
+ // IN register, written from CPU: <enable 1:0> <status 7:0> <inp 7:0>
|
|
|
+ // Busy register:
|
|
|
+ //
|
|
|
+ // [7:0] - busy OUT status (write-1-clear)
|
|
|
+ // [9:8] - busy IN status (write-1-clear)
|
|
|
+ // [15] - bus status change (write-1-clear)
|
|
|
+ //
|
|
|
+ // [23:16] - busy OUT mask
|
|
|
+ // [25:24] - busy IN mask
|
|
|
+ // [31] - bus status change IRQ enable
|
|
|
+ //
|
|
|
+ // Assert WAIT# (deassert RDY) if the masked busy status is nonzero
|
|
|
+ // and an busy-unmasked I/O comes in.
|
|
|
+ //
|
|
|
+ // An IRQ is generated if the masked busy status is nonzero.
|
|
|
+ //
|
|
|
+ reg [9:0] busy_status;
|
|
|
+ reg [9:0] busy_mask;
|
|
|
+ reg [1:0] inp_en;
|
|
|
+ reg bus_change_status;
|
|
|
+ reg bus_change_mask;
|
|
|
+
|
|
|
+ wire [9:0] busy_io = { abc_inp[1:0], abc_rst, 1'b0,
|
|
|
+ abc_out[4:1], abc_cs, abc_out[0] };
|
|
|
+
|
|
|
+ wire [9:0] set_busy = busy_io & busy_mask;
|
|
|
+ wire is_busy = |(busy_status & busy_mask);
|
|
|
+
|
|
|
+ // WAIT# logic
|
|
|
+ reg abc_wait_force = 1'b0; // Not cleared on internal reset!
|
|
|
+
|
|
|
+ always @(posedge sys_clk)
|
|
|
+ abc_wait <= abc_wait_force | (rst_n & |set_busy & is_busy);
|
|
|
|
|
|
- // I/O status bits: sets the irq_status bits (sticky, write-1-clear)
|
|
|
- // The RST# (INP 7) and CS# (OUT 1) signals are always valid
|
|
|
- // regardless of the current select code; OUT 0/INP 0 only
|
|
|
- // set the bit once the DMA counter reaches or already is zero.
|
|
|
-
|
|
|
- wire [7:0] abc_inpflag = { abc_rst, 5'b00000,
|
|
|
- abc_iord_en & abc_rden & abc_inp[1],
|
|
|
- abc_iord_en & abc_rden & ~abc_dma_nzero & abc_inp[0] };
|
|
|
- wire [7:0] abc_outflag = { 2'b00,
|
|
|
- {4{abc_iowr_en & abc_wren}} & abc_out[4:1],
|
|
|
- abc_cs,
|
|
|
- abc_iowr_en & abc_wren & ~abc_dma_nzero & abc_out[0] };
|
|
|
-
|
|
|
- // DMA status register: set on *any* DMA access.
|
|
|
- // bit 0 = out DMA; bit 1 = in DMA.
|
|
|
- wire [1:0] abc_dmaflag = { abc_iord_en & abc_rden & abc_dma_en,
|
|
|
- abc_iowr_en & abc_wren & abc_dma_en };
|
|
|
//
|
|
|
- // ABC-bus data bus handling
|
|
|
+ // I/O data registers
|
|
|
//
|
|
|
- always @(posedge sdram_clk or negedge rst_n)
|
|
|
+ reg [2:0] reg_out_addr;
|
|
|
+ reg [7:0] reg_out_data;
|
|
|
+ reg [7:0] reg_inp_data[0:1];
|
|
|
+
|
|
|
+ // OUT logic
|
|
|
+ always @(posedge sdram_clk)
|
|
|
+ begin
|
|
|
+ if (|busy_io[7:0])
|
|
|
+ begin
|
|
|
+ reg_out_data <= abc_di;
|
|
|
+ case (busy_io[7:0])
|
|
|
+ 8'b0000_0001: reg_out_addr <= 3'd0;
|
|
|
+ 8'b0000_0010: reg_out_addr <= 3'd1;
|
|
|
+ 8'b0000_0100: reg_out_addr <= 3'd2;
|
|
|
+ 8'b0000_1000: reg_out_addr <= 3'd3;
|
|
|
+ 8'b0001_0000: reg_out_addr <= 3'd4;
|
|
|
+ 8'b0010_0000: reg_out_addr <= 3'd5;
|
|
|
+ 8'b0100_0000: reg_out_addr <= 3'd6;
|
|
|
+ 8'b1000_0000: reg_out_addr <= 3'd7;
|
|
|
+ default: reg_out_addr <= 3'dx;
|
|
|
+ endcase // case (busy_io)
|
|
|
+ end // if (|busy_io[7:0])
|
|
|
+ end // always @ (posedge sdram_clk)
|
|
|
+
|
|
|
+ //
|
|
|
+ // ABC data out (= ABC host read) logic
|
|
|
+ //
|
|
|
+ always @(negedge rst_n or posedge sdram_clk)
|
|
|
if (~rst_n)
|
|
|
begin
|
|
|
- abc_do <= 8'hxx;
|
|
|
abc_d_oe <= 1'b0;
|
|
|
- end
|
|
|
- else if (abc_inp[1] & abc_iord_en & abc_rden)
|
|
|
- begin
|
|
|
- abc_do <= status_out;
|
|
|
- abc_d_oe <= 1'b1;
|
|
|
- end
|
|
|
- else if (abc_racked & sdram_rready)
|
|
|
- begin
|
|
|
- abc_do <= sdram_rd;
|
|
|
- abc_d_oe <= 1'b1;
|
|
|
+ abc_do <= 8'bx;
|
|
|
end
|
|
|
else
|
|
|
begin
|
|
|
- abc_do <= 8'hxx;
|
|
|
abc_d_oe <= 1'b0;
|
|
|
- end
|
|
|
+ abc_do <= 8'bx;
|
|
|
+
|
|
|
+ if (abc_xmemrd & sdram_rready)
|
|
|
+ begin
|
|
|
+ abc_d_oe <= 1'b1;
|
|
|
+ abc_do <= sdram_rd;
|
|
|
+ end
|
|
|
+ else if (abc_inp[0] & inp_en[0])
|
|
|
+ begin
|
|
|
+ abc_d_oe <= 1'b1;
|
|
|
+ abc_do <= reg_inp_data[0];
|
|
|
+ end
|
|
|
+ else if (abc_inp[1] & inp_en[1])
|
|
|
+ begin
|
|
|
+ abc_d_oe <= 1'b1;
|
|
|
+ abc_do <= reg_inp_data[1];
|
|
|
+ end
|
|
|
+ end // else: !if(~rst_n)
|
|
|
+
|
|
|
+ // Bus status
|
|
|
+ reg [31:0] abc_status[0:1];
|
|
|
+
|
|
|
+ always @(posedge sys_clk)
|
|
|
+ begin
|
|
|
+ abc_status[0] <= { 29'b0, abc800, abc_rst_s, abc_clk_active };
|
|
|
+ abc_status[1] <= abc_status[0];
|
|
|
+ end
|
|
|
|
|
|
+ wire bus_change = |(abc_status[0] ^ abc_status[1]);
|
|
|
+
|
|
|
//
|
|
|
- // ABC-bus control/status registers
|
|
|
- // All these registers are 32-bit access only except the I/O status
|
|
|
- // register (which is write-1-clear.)
|
|
|
+ // Busy/IRQ status and CPU register writes
|
|
|
//
|
|
|
- reg clear_irq;
|
|
|
- reg [31:0] irq_mask;
|
|
|
-
|
|
|
always @(posedge sys_clk or negedge rst_n)
|
|
|
if (~rst_n)
|
|
|
begin
|
|
|
- abc_iobase <= 20'bx;
|
|
|
- irq_mask <= 32'b0;
|
|
|
- clear_irq <= 1'b0;
|
|
|
- // abc_resin, nmi, int and wait are deliberately not affected
|
|
|
+ busy_status <= 10'b0;
|
|
|
+ busy_mask <= 10'b0;
|
|
|
+ inp_en <= 2'b00;
|
|
|
+ bus_change_status <= 1'b0;
|
|
|
+ bus_change_mask <= 1'b0;
|
|
|
+
|
|
|
+ // abc_resin, nmi, int and force_wait are deliberately not affected
|
|
|
// by an internal CPU reset. They are, however, initialized
|
|
|
// to 0 on a CPU init (see above.)
|
|
|
end
|
|
|
else
|
|
|
begin
|
|
|
- clear_irq <= 1'b0;
|
|
|
-
|
|
|
- if (abc_valid & cpu_wstrb[0])
|
|
|
+ busy_status <= busy_status | set_busy;
|
|
|
+ bus_change_status <= bus_change_status | bus_change;
|
|
|
+
|
|
|
+ if (abc_valid)
|
|
|
begin
|
|
|
- casez (cpu_addr[5:2])
|
|
|
- 5'b??010:
|
|
|
- abc_iobase <= cpu_wdata[24:4];
|
|
|
- 5'b??011:
|
|
|
- { abc_resin, abc_nmi, abc_int, abc_wait } <= cpu_wdata[3:0];
|
|
|
- 5'b??100:
|
|
|
- irq_mask <= cpu_wdata;
|
|
|
- 5'b??101:
|
|
|
- clear_irq <= 1'b1;
|
|
|
+ casez (cpu_addr[5:2] )
|
|
|
+ 5'b??010: begin
|
|
|
+ if (cpu_wstrb[0])
|
|
|
+ busy_status[7:0] <= set_busy[7:0] | (busy_status[7:0] & ~cpu_wdata[7:0]);
|
|
|
+ if (cpu_wstrb[1])
|
|
|
+ begin
|
|
|
+ busy_status[9:8] <= set_busy[9:8] | (busy_status[9:8] & ~cpu_wdata[9:8]);
|
|
|
+ bus_change_status <= bus_change | (bus_change_status & ~cpu_wdata[15]);
|
|
|
+ end
|
|
|
+ if (cpu_wstrb[2])
|
|
|
+ busy_mask[7:0] <= cpu_wdata[23:16] & ~8'h40;
|
|
|
+ if (cpu_wstrb[3])
|
|
|
+ begin
|
|
|
+ busy_mask[9:8] <= cpu_wdata[25:24];
|
|
|
+ bus_change_mask <= cpu_wdata[31];
|
|
|
+ end
|
|
|
+ end
|
|
|
+ 5'b???011: begin
|
|
|
+ if (cpu_wstrb[0])
|
|
|
+ begin
|
|
|
+ abc_resin <= cpu_wdata[3];
|
|
|
+ abc_nmi <= cpu_wdata[2];
|
|
|
+ abc_int <= cpu_wdata[1];
|
|
|
+ abc_wait_force <= cpu_wdata[0];
|
|
|
+ end
|
|
|
+ end
|
|
|
+ 5'b???101: begin
|
|
|
+ if (cpu_wstrb[0])
|
|
|
+ reg_inp_data[0] <= cpu_wdata[7:0];
|
|
|
+ if (cpu_wstrb[1])
|
|
|
+ reg_inp_data[1] <= cpu_wdata[15:8];
|
|
|
+ if (cpu_wstrb[2])
|
|
|
+ inp_en <= cpu_wdata[17:16];
|
|
|
+ end
|
|
|
default:
|
|
|
/* do nothing */ ;
|
|
|
endcase // casez (cpu_addr[5:2])
|
|
|
end // if (abc_valid & cpu_wstrb[0])
|
|
|
end
|
|
|
|
|
|
- reg [2:0] abc_status[0:1];
|
|
|
-
|
|
|
- always @(posedge sys_clk)
|
|
|
- begin
|
|
|
- abc_status[0] <= { 5'b0, abc800, abc_rst_s, abc_clk_active };
|
|
|
- abc_status[1] <= abc_status[0];
|
|
|
- end
|
|
|
-
|
|
|
- wire [31:0] irq_status_in = { 5'b0, abc_status[1] ^ abc_status[0],
|
|
|
- 6'b0, abc_dmaflag,
|
|
|
- abc_inpflag,
|
|
|
- abc_outflag };
|
|
|
- reg [31:0] irq_status;
|
|
|
- wire [31:0] irq_status_mask = 32'h07_03_83_3f; // Valid status bits
|
|
|
-
|
|
|
- always @(negedge rst_n or posedge sys_clk)
|
|
|
- if (~rst_n)
|
|
|
- irq_status <= 32'b0;
|
|
|
- else
|
|
|
- irq_status <= ( irq_status_in & irq_status_mask ) |
|
|
|
- (irq_status & ~({32{clear_irq}} & cpu_wdata));
|
|
|
-
|
|
|
// Level triggered IRQ
|
|
|
- always @(negedge rst_n or posedge sys_clk)
|
|
|
- if (~rst_n)
|
|
|
- irq <= 1'b0;
|
|
|
- else
|
|
|
- irq <= |(irq_status & irq_mask);
|
|
|
+ always @(posedge sys_clk)
|
|
|
+ irq <= is_busy | (bus_change_status & bus_change_mask);
|
|
|
|
|
|
// Read MUX
|
|
|
always_comb
|
|
|
casez (cpu_addr[5:2])
|
|
|
- 5'b00000: cpu_rdata = { 24'b0, abc_status[0] };
|
|
|
+ 5'b00000: cpu_rdata = abc_status[0];
|
|
|
5'b00001: cpu_rdata = { 23'b0, ~iosel_en, ioselx[7:0] };
|
|
|
- 5'b00010: cpu_rdata = abc_iobase;
|
|
|
+ 5'b00010: cpu_rdata = { 6'b0, busy_mask, 6'b0, busy_status };
|
|
|
5'b00011: cpu_rdata = { 28'b0, abc_resin, abc_nmi, abc_int, abc_wait };
|
|
|
- 5'b00100: cpu_rdata = irq_mask & irq_status_mask;
|
|
|
- 5'b00101: cpu_rdata = irq_status;
|
|
|
+ 5'b00100: cpu_rdata = { 21'b0, reg_out_addr, reg_out_data };
|
|
|
+ 5'b00101: cpu_rdata = { 14'b0, inp_en, reg_inp_data[1], reg_inp_data[0] };
|
|
|
default: cpu_rdata = 32'bx;
|
|
|
endcase // casez (cpu_addr[5:2])
|
|
|
|