|
@@ -108,16 +108,27 @@ module abcbus (
|
|
|
wire abc80 = abc_xinpstb_s & abc_xoutpstb_s;
|
|
|
wire abc800 = ~abc80;
|
|
|
|
|
|
- // Memory read/write strobes
|
|
|
- wire abc_xmemrd = abc_clk_active & abc_xmemfl_s;
|
|
|
- wire abc_xmemwr = abc_clk_active &
|
|
|
+ // Memory and I/O read/write strobes for ABC-bus
|
|
|
+ reg abc_xmemrd;
|
|
|
+ reg abc_xmemwr;
|
|
|
+ reg [1:0] abc_inp;
|
|
|
+ reg [4:0] abc_out;
|
|
|
+ reg abc_rst;
|
|
|
+ reg abc_cs;
|
|
|
+ reg [3:1] abc_stb; // Delayed strobes
|
|
|
+
|
|
|
+ always @(posedge sdram_clk)
|
|
|
+ begin
|
|
|
+ abc_xmemrd <= abc_clk_active & abc_xmemfl_s;
|
|
|
+ abc_xmemwr <= abc_clk_active &
|
|
|
(abc800 ? abc_xmemw800_s : abc_xmemw80_s);
|
|
|
-
|
|
|
- // I/O read/write strobes for ABC-bus only
|
|
|
- wire [2:0] abc_inp = abc_inp_s & {3{abc_clk_active}} & {abc800, 2'b11};
|
|
|
- wire [4:0] abc_out = abc_out_s & {5{abc_clk_active}};
|
|
|
- wire abc_rst = abc_rst_s & abc_clk_active;
|
|
|
- wire abc_cs = abc_cs_s & abc_clk_active;
|
|
|
+ abc_inp <= abc_inp_s & {2{abc_clk_active}};
|
|
|
+ abc_out <= abc_out_s & {5{abc_clk_active}};
|
|
|
+ abc_rst <= abc_rst_s & abc_clk_active;
|
|
|
+ abc_cs <= abc_cs_s & abc_clk_active;
|
|
|
+ abc_stb <= { abc_stb, |{abc_inp, abc_out, abc_rst,
|
|
|
+ abc_cs, abc_xmemrd, abc_xmemwr} };
|
|
|
+ end
|
|
|
|
|
|
reg [7:0] abc_do;
|
|
|
assign abc_d = abc_d_oe ? abc_do : 8'hzz;
|
|
@@ -258,16 +269,12 @@ module abcbus (
|
|
|
//
|
|
|
// However, the rd and wr enable bits in the I/O map still apply.
|
|
|
//
|
|
|
- wire [24:0] abc_memaddr;
|
|
|
-
|
|
|
wire [7:0] abc_map_addr =
|
|
|
- abc_out_s[0] ? { 1'b1, iosel, 1'b0 } :
|
|
|
- abc_inp_s[0] ? { 1'b1, iosel, 1'b1 } :
|
|
|
+ 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 [8:0] abc_dma_count;
|
|
|
wire [35:0] rdata_abcmemmap;
|
|
|
- wire abc_rden;
|
|
|
- wire abc_wren;
|
|
|
+ wire [35:0] abc_memmap_rd;
|
|
|
|
|
|
//
|
|
|
// For I/O, don't allow the read/write enables to conflict with
|
|
@@ -288,8 +295,7 @@ module abcbus (
|
|
|
abc_memaddr + 1'b1 } ),
|
|
|
.wren_a ( abc_dma_update ),
|
|
|
.byteena_a ( 4'b1111 ),
|
|
|
- .q_a ( { abc_dma_count,
|
|
|
- abc_rden, abc_wren, abc_memaddr } ),
|
|
|
+ .q_a ( abc_memmap_rd ),
|
|
|
|
|
|
.address_b ( cpu_addr[9:2] ),
|
|
|
.data_b ( { cpu_wdata[8:0],
|
|
@@ -302,6 +308,28 @@ module abcbus (
|
|
|
.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;
|
|
|
+
|
|
|
+ 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
|
|
|
+
|
|
|
assign cpu_rdata_map = cpu_addr[10] ?
|
|
|
{ 23'b0, rdata_abcmemmap[35:27] } :
|
|
|
{ rdata_abcmemmap[26:25], 5'b0,
|
|
@@ -322,41 +350,33 @@ module abcbus (
|
|
|
wire abc_wack;
|
|
|
wire abc_rready;
|
|
|
|
|
|
- // I/O status register: set on valid access, trigger IRQ.
|
|
|
- // 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 zero, if applicable.
|
|
|
- reg [7:0] abc_inpflag;
|
|
|
- wire [7:0] clear_inpflag;
|
|
|
- reg [7:0] abc_outflag;
|
|
|
- wire [7:0] clear_outflag;
|
|
|
-
|
|
|
always @(posedge sdram_clk or negedge rst_n)
|
|
|
if (~rst_n)
|
|
|
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_inpflag <= 8'b0;
|
|
|
- abc_outflag <= 8'b0;
|
|
|
+ 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
|
|
|
- // Careful with the registering here; need to make sure
|
|
|
- // abcmapram is caught up
|
|
|
+ // Careful with the registering here: need to make sure
|
|
|
+ // abcmapram is caught up for I/O; for memory the address
|
|
|
+ // 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_iowr_en <= iosel_en & |abc_out;
|
|
|
- abc_iord_en <= iosel_en & |abc_inp;
|
|
|
+ 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_do_memwr <= abc_wren & (abc_memwr_en | abc_iowr_en);
|
|
@@ -370,19 +390,9 @@ module abcbus (
|
|
|
abc_dma_update <= abc_dma_en &
|
|
|
((sdram_rrq & abc_racked) |
|
|
|
(sdram_wrq & abc_wacked));
|
|
|
-
|
|
|
- abc_inpflag <= ~clear_inpflag &
|
|
|
- (abc_inpflag |
|
|
|
- { abc_rst, 4'b0000,
|
|
|
- {2{abc_iord_en}} & abc_inp[2:1],
|
|
|
- abc_iord_en & ~|abc_dma_count & abc_inp[0] });
|
|
|
- abc_outflag <= ~clear_outflag &
|
|
|
- (abc_outflag |
|
|
|
- { 2'b00, {4{abc_iowr_en}} & abc_out[4:1],
|
|
|
- abc_cs,
|
|
|
- abc_iowr_en & ~|abc_dma_count & abc_out[0] });
|
|
|
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] } :
|
|
@@ -390,6 +400,23 @@ module abcbus (
|
|
|
|
|
|
assign sdram_wd = abc_di;
|
|
|
|
|
|
+ // 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_inp[1],
|
|
|
+ abc_iord_en & ~abc_dma_nzero & abc_inp[0] };
|
|
|
+ wire [7:0] abc_outflag = { 2'b00,
|
|
|
+ {4{abc_iowr_en}} & abc_out[4:1],
|
|
|
+ abc_cs,
|
|
|
+ abc_iowr_en & ~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_dma_en,
|
|
|
+ abc_iowr_en & abc_dma_en };
|
|
|
//
|
|
|
// ABC-bus data bus handling
|
|
|
//
|
|
@@ -415,54 +442,73 @@ module abcbus (
|
|
|
// All these registers are 32-bit access only except the I/O status
|
|
|
// register (which is write-1-clear.)
|
|
|
//
|
|
|
- assign clear_inpflag = {8{abc_valid & cpu_addr[5:2] == 5'b00011
|
|
|
- & cpu_wstrb[1]}} & cpu_wdata[15:8];
|
|
|
- assign clear_outflag = {8{abc_valid & cpu_addr[5:2] == 5'b00011
|
|
|
- & cpu_wstrb[0]}} & cpu_wdata[7:0];
|
|
|
+ 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;
|
|
|
end
|
|
|
- else if (abc_valid & cpu_wstrb[0])
|
|
|
+ else
|
|
|
begin
|
|
|
- casez (cpu_addr[5:2])
|
|
|
- 5'b???10:
|
|
|
- abc_iobase <= cpu_wdata[24:4];
|
|
|
- default:
|
|
|
- /* do nothing */ ;
|
|
|
- endcase
|
|
|
+ clear_irq <= 1'b0;
|
|
|
+
|
|
|
+ if (abc_valid & cpu_wstrb[0])
|
|
|
+ begin
|
|
|
+ casez (cpu_addr[5:2])
|
|
|
+ 5'b??010:
|
|
|
+ abc_iobase <= cpu_wdata[24:4];
|
|
|
+ 5'b??100:
|
|
|
+ irq_mask <= cpu_wdata;
|
|
|
+ 5'b??100:
|
|
|
+ clear_irq <= 1'b1;
|
|
|
+ default:
|
|
|
+ /* do nothing */ ;
|
|
|
+ endcase // casez (cpu_addr[5:2])
|
|
|
+ end // if (abc_valid & cpu_wstrb[0])
|
|
|
end
|
|
|
|
|
|
- reg [31:0] abc_status[0:1];
|
|
|
+ reg [2: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];
|
|
|
+ abc_status[0] <= { 5'b0, abc800, abc_rst_s, abc_clk_active };
|
|
|
+ abc_status[1] <= abc_status[0];
|
|
|
end
|
|
|
|
|
|
- wire [15:0] abc_iostatus = { abc_inpflag, abc_outflag };
|
|
|
- reg [15:0] abc_iostatus_q;
|
|
|
- always @(posedge sys_clk)
|
|
|
- abc_iostatus_q <= abc_iostatus;
|
|
|
+ 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);
|
|
|
|
|
|
+ // Read MUX
|
|
|
always_comb
|
|
|
casez (cpu_addr[5:2])
|
|
|
- 5'b00000: cpu_rdata = abc_status[0];
|
|
|
+ 5'b00000: cpu_rdata = { 24'b0, abc_status[0] };
|
|
|
5'b00001: cpu_rdata = ioselx[7:0];
|
|
|
5'b00010: cpu_rdata = abc_iobase;
|
|
|
- 5'b00011: cpu_rdata = { 16'b0, abc_iostatus };
|
|
|
+ 5'b00100: cpu_rdata = irq_mask & irq_status_mask;
|
|
|
+ 5'b00101: cpu_rdata = irq_status;
|
|
|
default: cpu_rdata = 32'bx;
|
|
|
endcase // casez (cpu_addr[5:2])
|
|
|
|
|
|
- // irq is edge-triggered on either changes to abc_status
|
|
|
- // or bits set in iostatus.
|
|
|
- always @(negedge rst_n or posedge sys_clk)
|
|
|
- if (~rst_n)
|
|
|
- irq <= 1'b0;
|
|
|
- else
|
|
|
- irq <= (abc_status[1] != abc_status[0]) |
|
|
|
- (|(abc_iostatus & ~abc_iostatus_q));
|
|
|
-
|
|
|
endmodule // abcbus
|