// part of NeoGS project
//
// (c) NedoPC 2007-2009
//
// ZX dma controller
//
// includes dma address regs, dma control reg
//
module dma_zx(
input clk,
input rst_n,
// ZXBUS-related signals
input dma_zxread_toggle;
input dma_zxwrite_toggle;
output reg dma_reswait_n;
input [7:0] dma_data_written;
output reg [7:0] dma_data_toberead;
// different global & control signals
output reg dma_on;
// signals from ports.v
input [7:0] din; // input and output from ports.v
output reg [7:0] dout;
input module_select; // =1 - module selected for read-write operations from ports.v
input write_strobe; // one-cycle positive write strobe - writes to the selected registers from din
input [1:0] regsel; // 2'b00 - high address, 2'b01 - middle address, 2'b10 - low address, 2'b11 - control register
// signals for DMA controller
output reg [20:0] dma_addr;
output reg [7:0] dma_wd;
input [7:0] dma_rd;
output reg dma_rnw;
output reg dma_req;
input dma_ack;
input dma_done;
);
wire zxrd,zxwr; // zx read and write indicators, =1 when zx just done the thing. must be cleared.
reg zxoldrd,zxoldwr;
reg zxclr; // clear zxrd or zxwr
reg [2:0] zxrdtgl, zxwrtgl; // syncing in dma_zx(read|write)_toggle
//zxrd or zxwr first set to 1 when zx**tgl[2]!=zx**tgl[1], then it supported in 1 state from zxold** flipflop
//by asserting zxclr=1 for 1 cycle, zxold** are both cleared.
localparam _HAD = 2'b00; // high address
localparam _MAD = 2'b01; // mid address
localparam _LAD = 2'b10; // low address
localparam _CST = 2'b11; // control and status
// control dout bus
always @*
case( regsel[1:0] )
_HAD: dout = { 3'b000, dma_addr[20:16] };
_MAD: dout = dma_addr[15:8];
_LAD: dout = dma_addr[7:0];
_CST: dout = { dma_on, 7'bXXXXXXX };
endcase
// ports.v write access & dma_addr control
always @(posedge clk, negedge rst_n)
if( !rst_n ) // async reset
begin
dma_on <= 1'b0;
end
else // posedge clk
begin
// dma_on control
if( module_select && write_strobe && (regsel==_CST) )
dma_on <= din[7];
// dma_addr control
if( dma_ack && dma_on )
dma_addr <= dma_addr + 20'd1; // increment on beginning of DMA transfer
else if( module_select && write_strobe )
begin
if( regsel==_HAD )
dma_addr[20:16] <= din[4:0];
else if( regsel==_MAD )
dma_addr[15:8] <= din[7:0];
else if( regsel==_LAD )
dma_addr[7:0] <= din[7:0];
end
end
// dma_zx(read|write)_toggle syncing in and zxrd/zxwr strobes
always @(posedge clk,negedge rst_n)
if( !rst_n )
begin
zxoldrd <= 1'b0;
zxoldwr <= 1'b0;
end
else //posedge clk
begin
if( dma_on )
begin
if( zxrdtgl[2] != zxrdtgl[1] )
zxoldrd <= 1'b1;
else if( zxclr )
zxoldrd <= 1'b0;
if( zxwrtgl[2] != zxwrtgl[1] )
zxoldwr <= 1'b1;
else if( zxclr )
zxoldwr <= 1'b0;
end
else
begin
zxoldrd <= 1'b0;
zxoldwr <= 1'b0;
end
end
always @(posedge clk)
begin
zxrdtgl[2:0] <= { zxrdtgl[1:0], dma_zxread_toggle };
zxwrtgl[2:0] <= { zxwrtgl[1:0], dma_zxwrite_toggle };
end
assign zxrd = ( zxrdtgl[2] != zxrdtgl[1] ) | zxoldrd;
assign zxwr = ( zxwrtgl[2] != zxwrtgl[1] ) | zxoldwr;
endmodule