pi.v 5.36 KB
// pi.v v1 Frank Berndt
// pi top level;

	...

	// memory address;
	// must be 16-bit aligned for compatibility;
	// loaded with pio write write;
	// used for first dma block transfer to align;
	// then increments in blocks of 128 bytes;

	wire dma_addr_we;		// write dma address;
	wire dma_addr_ld;		// load dma address;
	wire dma_addr_inc;		// increment dma address;

	assign dma_addr_we = reg_write & ra_dma_addr;
	assign dma_addr_ld = ~dma_conflict & dma_addr_we;

	always @(posedge sysclk)
	begin
		if(dma_addr_ld)
			dma_addr <= { pio_wdata[25:1], 1'b0 };
		else if(dma_addr_inc)
			dma_addr <= { dma_addr[25:7] + 1, 7'd0 };
	end

	// device address;
	// virtual or physical address into device space;
	// compatibility requires 16-bit alignment;
	// however, bit 0 is needed for new functions;

	wire dev_addr_we;		// write device address;
	wire dev_addr_ld;		// load device address;
	wire dev_addr_inc;		// increment device address;

	assign dev_addr_we = reg_write & ra_dev_addr;
	assign dev_addr_ld = ~dma_conflict & dev_addr_we;

	always @(posedge sysclk)
	begin
		if(dev_addr_ld)
			dev_addr <= pio_wdata[29:0];
		else if(io_write)
			dev_addr <= pio_addr;
		else if(dev_addr_inc)
			dev_addr[29:3] <= dev_addr[29:3] + 1;
	end

	// dma length;
	// writing the dma length registers starts the dma;
	// starting a dma through PI_DMA_READ triggers error interrupt;
	// it is up to software to emulate the write;
	// one clock later, add lower addres bits for # of dw;
	// decremented by buffer dma for each double-word;
	// do not start dma when dma_len is 0, but issue done;

	wire dma_len_we;		// write to dma length;
	wire dma_len_ld;		// load dma_len;
	wire dma_proc;			// start write dma process;
	wire dma_trap;			// trap read dma;
	reg dma_kick;			// kick dma;
	wire dma_len_dec;		// decrement dma length;
	wire dma_len_nw0;		// # of dw is 0;
	reg dma_len_zero;		// dma length is 0;
	wire [23:0] dma_off;	// lower byte offset;

	assign dma_len_we = reg_write & ra_dma_len;
	assign dma_len_ld = ~dma_conflict & dma_len_we;
	assign dma_off = { 21'd0, dma_addr[2:1], 1'b0 };
	assign dma_len_nw0 = (dma_len[23:3] == 21'd0);

	always @(posedge sysclk)
	begin
		dma_kick <= dma_len_ld;
		if(dma_len_ld) begin
			dma_read <= ra_dma_read | ra_bread;
			dma_rwb <= ra_bread | ra_bwrite;
		end
		if(dma_len_ld)
			dma_len <= pio_wdata[23:0];
		else if(dma_kick)
			dma_len <= dma_len + dma_off;
		else if(dma_len_dec)
			dma_len[23:3] <= dma_len[23:3] - 1;
		if(io_kick)
			dma_len_zero <= 1'b0;
		else if(dma_kick)
			dma_len_zero <= &dma_len;
		else if(dma_len_dec)
			dma_len_zero <= dma_len_nw0;
	end

	....

	// dma burst length;
	// first burst aligns to 128-byte block;
	// a number of full 128-byte bursts may follow;
	// last burst moves the remaining bytes;

	wire bdma_ge128;		// dma_len >= 128;
	wire [6:3] bdma_dwib;	// # of dw in current burst;
	reg bdma_fill;			// fill current burst;
	reg [6:0] bdma_len;		// burst dma length;

	assign bdma_ge128 = |dma_len[23:7];
	assign bdma_dwib = ~dma_addr[6:3];

	always @(posedge sysclk)
	begin
		bdma_fill <= bdma_ge128 | (dma_len[6:3] > bdma_dwib);
		bdma_len <= bdma_fill? { bdma_dwib, 3'b111 } : dma_len[6:0];
	end

	// request dbus dma;

	reg bdma_aesp;			// aesp requests one burst dma;
	wire bdma_req;			// dma burst request;
	wire bdma_cyc_clr;		// clear bdma busy;
	reg bdma_cyc;			// bdma busy;
	wire bdma_req_clr;		// clear dma request;
	reg dma_request;		// dma request;
	reg bdma_ack;			// burst dma ack;
	reg bdma_ack2;
	reg bdma_ack3;

	assign bdma_cyc_clr = dma_stop | bdma_ack3;
	assign bdma_req_clr = dma_stop | dma_grant;
	assign bdma_req = dma_busy & ~dma_len_zero & ~bdma_cyc & (bdma_aesp | bdma_busy);

	always @(posedge sysclk)
	begin
		bdma_cyc <= ~bdma_cyc_clr & (bdma_cyc | bdma_req);
		dma_request <= ~bdma_req_clr & (dma_request | bdma_req);
		bdma_ack <= dma_last;
		bdma_ack2 <= bdma_ack;
		bdma_ack3 <= bdma_ack2;
	end

	// burst dma control;

	reg bdma_dph;			// burst dma phase;
	wire bdma_val;			// burst dma data valid;
	reg [1:0] bdma_dval;	// delayed valid;
	wire dbus_shr;			// data right shift;

	always @(posedge sysclk)
	begin
		bdma_dph <= bdma_cyc & ~dma_last & (bdma_dph | dma_start);
		bdma_dval <= { bdma_dval[0], bdma_val };
	end

	assign bdma_val = dma_start | bdma_dph;
	assign dma_len_dec = bdma_dval[0];
	assign dma_addr_inc = bdma_ack;
	assign dev_addr_inc = bdma_dval[0];

	....

	// aes data count;
	// amount of data that has passed the aes process;
	// kick burst dma when enough data to fill a dma cycle;

	wire dev_off_nz;		// dev_addr not aligned to aes blocks;
	reg [10:1] aesp_cnt;	// data count;
	wire aesp_cnt_inc;		// aes done with another double-word;
	wire aesp_cnt_dec;		// bdma moved another word;

	assign dev_off_nz = (dev_addr[3:1] != 3'd0);

	always @(posedge sysclk)
	begin
		if(proc_start) begin
			aesp_cnt[10:4] <= {7{dev_off_nz}};
			aesp_cnt[3:1] <= (~dev_addr[3:1] + 1);
		end if(aesp_cnt_inc & ~aesp_cnt_dec)
			aesp_cnt <= aesp_cnt + 4;
		else if(aesp_cnt_dec & ~aesp_cnt_inc)
			aesp_cnt <= aesp_cnt - 4;
		bdma_aesp <= proc_busy & ~aesp_cnt[10]
			& (aesp_cnt[9:1] > { 3'd0, bdma_len[6:1] });
	end

	assign aesp_cnt_inc = aes_dw;
	assign aesp_cnt_dec = bdma_dval[0];
	assign proc_rblk = ~aesp_cnt[10] & |aesp_cnt[9:8];

	// assertions;
	// synopsys translate_off

	always @(posedge sysclk)
	begin
		if(proc_busy & aesp_cnt[10] & aesp_cnt_dec)
			$display("ERROR: %t: %M: bdma overran aes", $time);
	end

	// synopsys translate_on

endmodule