OpenCores
URL https://opencores.org/ocsvn/zipcpu/zipcpu/trunk

Subversion Repositories zipcpu

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /zipcpu/trunk/rtl/peripherals
    from Rev 160 to Rev 144
    Reverse comparison

Rev 160 → Rev 144

/wbdmac.v
81,9 → 81,12
// Creator: Dan Gisselquist
// Gisselquist Technology, LLC
//
// Copyright: 2015
//
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
// Copyright (C) 2015, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
102,15 → 105,7
///////////////////////////////////////////////////////////////////////////
//
//
`define DMA_IDLE 3'b000
`define DMA_WAIT 3'b001
`define DMA_READ_REQ 3'b010
`define DMA_READ_ACK 3'b011
`define DMA_PRE_WRITE 3'b100
`define DMA_WRITE_REQ 3'b101
`define DMA_WRITE_ACK 3'b110
 
module wbdmac(i_clk, i_rst,
module wbdmac(i_clk,
i_swb_cyc, i_swb_stb, i_swb_we, i_swb_addr, i_swb_data,
o_swb_ack, o_swb_stall, o_swb_data,
o_mwb_cyc, o_mwb_stb, o_mwb_we, o_mwb_addr, o_mwb_data,
119,7 → 114,7
o_interrupt);
parameter ADDRESS_WIDTH=32, LGMEMLEN = 10,
DW=32, LGDV=5,AW=ADDRESS_WIDTH;
input i_clk, i_rst;
input i_clk;
// Slave/control wishbone inputs
input i_swb_cyc, i_swb_stb, i_swb_we;
input [1:0] i_swb_addr;
129,7 → 124,7
output wire o_swb_stall;
output reg [(DW-1):0] o_swb_data;
// Master/DMA wishbone control
output wire o_mwb_cyc, o_mwb_stb, o_mwb_we;
output reg o_mwb_cyc, o_mwb_stb, o_mwb_we;
output reg [(AW-1):0] o_mwb_addr;
output reg [(DW-1):0] o_mwb_data;
// Master/DMA wishbone responses from the bus
150,8 → 145,8
//
 
 
reg [2:0] dma_state;
reg cfg_err, cfg_len_nonzero;
reg cfg_wp; // Write protect
reg cfg_err;
reg [(AW-1):0] cfg_waddr, cfg_raddr, cfg_len;
reg [(LGMEMLEN-1):0] cfg_blocklen_sub_one;
reg cfg_incs, cfg_incd;
162,253 → 157,134
// memory block here.
 
reg [(DW-1):0] dma_mem [0:(((1<<LGMEMLEN))-1)];
reg [(LGMEMLEN):0] nread, nwritten, nwacks, nracks;
wire [(AW-1):0] bus_nracks;
assign bus_nracks = { {(AW-LGMEMLEN-1){1'b0}}, nracks };
reg [(LGMEMLEN):0] nread, nwritten, nacks;
wire [(AW-1):0] bus_nacks;
assign bus_nacks = { {(AW-LGMEMLEN-1){1'b0}}, nacks };
 
reg last_read_request, last_read_ack,
last_write_request, last_write_ack;
reg trigger, abort;
 
initial dma_state = `DMA_IDLE;
initial o_interrupt = 1'b0;
initial o_mwb_cyc = 1'b0;
initial cfg_err = 1'b0;
initial cfg_wp = 1'b0;
initial cfg_len = {(AW){1'b0}};
initial cfg_blocklen_sub_one = {(LGMEMLEN){1'b1}};
initial cfg_on_dev_trigger = 1'b0;
initial cfg_len_nonzero = 1'b0;
always @(posedge i_clk)
case(dma_state)
`DMA_IDLE: begin
o_mwb_addr <= cfg_raddr;
nwritten <= 0;
nread <= 0;
nracks <= 0;
nwacks <= 0;
cfg_len_nonzero <= (|cfg_len);
 
// When the slave wishbone writes, and we are in this
// (ready) configuration, then allow the DMA to be controlled
// and thus to start.
if ((i_swb_cyc)&&(i_swb_stb)&&(i_swb_we))
if ((o_mwb_cyc)&&(o_mwb_we)) // Write cycle
begin
case(i_swb_addr)
2'b00: begin
if ((i_swb_data[27:16] == 12'hfed)
&&(cfg_len_nonzero))
dma_state <= `DMA_WAIT;
cfg_blocklen_sub_one
<= i_swb_data[(LGMEMLEN-1):0]
+ {(LGMEMLEN){1'b1}};
// i.e. -1;
cfg_dev_trigger <= i_swb_data[14:10];
cfg_on_dev_trigger <= i_swb_data[15];
cfg_incs <= ~i_swb_data[29];
cfg_incd <= ~i_swb_data[28];
if ((o_mwb_stb)&&(~i_mwb_stall))
begin
nwritten <= nwritten+1;
if (nwritten == nread-1)
// Wishbone interruptus
o_mwb_stb <= 1'b0;
else if (cfg_incd) begin
o_mwb_addr <= o_mwb_addr + 1;
cfg_waddr <= cfg_waddr + 1;
end
2'b01: begin
cfg_len <= i_swb_data[(AW-1):0];
cfg_len_nonzero <= (|i_swb_data[(AW-1):0]);
// o_mwb_data <= dma_mem[nwritten + 1];
end
 
if (i_mwb_err)
begin
o_mwb_cyc <= 1'b0;
cfg_err <= 1'b1;
cfg_len <= 0;
nread <= 0;
end else if (i_mwb_ack)
begin
nacks <= nacks+1;
cfg_len <= cfg_len - 1;
if ((nacks+1 == nwritten)&&(~o_mwb_stb))
begin
o_mwb_cyc <= 1'b0;
nread <= 0;
o_interrupt <= (cfg_len == 1);
// Turn write protect back on
cfg_wp <= 1'b1;
end
2'b10: cfg_raddr <= i_swb_data[(AW-1):0];
2'b11: cfg_waddr <= i_swb_data[(AW-1):0];
endcase
end end
`DMA_WAIT: begin
o_mwb_addr <= cfg_raddr;
nracks <= 0;
nwacks <= 0;
nwritten <= 0;
nread <= 0;
if (abort)
dma_state <= `DMA_IDLE;
else if (trigger)
dma_state <= `DMA_READ_REQ;
end
`DMA_READ_REQ: begin
nwritten <= 0;
 
if (~i_mwb_stall)
end
end else if ((o_mwb_cyc)&&(~o_mwb_we)) // Read cycle
begin
// Number of read acknowledgements needed
nracks <= nracks+1;
if (last_read_request)
//((nracks == {1'b0, cfg_blocklen_sub_one})||(bus_nracks == cfg_len-1))
// Wishbone interruptus
dma_state <= `DMA_READ_ACK;
if (cfg_incs)
o_mwb_addr <= o_mwb_addr
+ {{(AW-1){1'b0}},1'b1};
end
 
if (i_mwb_err)
begin
cfg_len <= 0;
dma_state <= `DMA_IDLE;
end
if (abort)
dma_state <= `DMA_IDLE;
if (i_mwb_ack)
begin
nread <= nread+1;
if (cfg_incs)
cfg_raddr <= cfg_raddr
+ {{(AW-1){1'b0}},1'b1};
end end
`DMA_READ_ACK: begin
nwritten <= 0;
 
if (i_mwb_err)
begin
cfg_len <= 0;
dma_state <= `DMA_IDLE;
end else if (i_mwb_ack)
begin
nread <= nread+1;
if (last_read_ack) // (nread+1 == nracks)
dma_state <= `DMA_PRE_WRITE;
if (cfg_incs)
cfg_raddr <= cfg_raddr
+ {{(AW-1){1'b0}},1'b1};
end
if (abort)
dma_state <= `DMA_IDLE;
end
`DMA_PRE_WRITE: begin
o_mwb_addr <= cfg_waddr;
dma_state <= (abort)?`DMA_IDLE:`DMA_WRITE_REQ;
end
`DMA_WRITE_REQ: begin
if (~i_mwb_stall)
begin
nwritten <= nwritten+1;
if (last_write_request) // (nwritten == nread-1)
// Wishbone interruptus
dma_state <= `DMA_WRITE_ACK;
if (cfg_incd)
if ((o_mwb_stb)&&(~i_mwb_stall))
begin
o_mwb_addr <= o_mwb_addr
+ {{(AW-1){1'b0}},1'b1};
cfg_waddr <= cfg_waddr
+ {{(AW-1){1'b0}},1'b1};
nacks <= nacks+1;
if ((nacks == {1'b0, cfg_blocklen_sub_one})
||(bus_nacks <= cfg_len-1))
// Wishbone interruptus
o_mwb_stb <= 1'b0;
else if (cfg_incs) begin
o_mwb_addr <= o_mwb_addr + 1;
end
end
end
 
if (i_mwb_err)
begin
cfg_len <= 0;
dma_state <= `DMA_IDLE;
end
if (i_mwb_ack)
begin
nwacks <= nwacks+1;
cfg_len <= cfg_len +{(AW){1'b1}}; // -1
end
if (abort)
dma_state <= `DMA_IDLE;
end
`DMA_WRITE_ACK: begin
if (i_mwb_err)
begin
cfg_len <= 0;
nread <= 0;
dma_state <= `DMA_IDLE;
end else if (i_mwb_ack)
begin
nwacks <= nwacks+1;
cfg_len <= cfg_len +{(AW){1'b1}};//cfg_len -= 1;
if (last_write_ack) // (nwacks+1 == nwritten)
if (i_mwb_err)
begin
o_mwb_cyc <= 1'b0;
cfg_err <= 1'b1;
cfg_len <= 0;
nread <= 0;
dma_state <= (cfg_len == 1)?`DMA_IDLE:`DMA_WAIT;
end else if (i_mwb_ack)
begin
nread <= nread+1;
if ((~o_mwb_stb)&&(nread+1 == nacks))
begin
o_mwb_cyc <= 1'b0;
nacks <= 0;
end
if (cfg_incs)
cfg_raddr <= cfg_raddr + 1;
// dma_mem[nread[(LGMEMLEN-1):0]] <= i_mwb_data;
end
end else if ((~o_mwb_cyc)&&(nread > 0)&&(~cfg_err))
begin // Initiate/continue a write cycle
o_mwb_cyc <= 1'b1;
o_mwb_stb <= 1'b1;
o_mwb_we <= 1'b1;
// o_mwb_data <= dma_mem[0];
o_mwb_addr <= cfg_waddr;
// nwritten <= 0; // Can't set to zero, in case we're
// nacks <= 0; // continuing a cycle
end else if ((~o_mwb_cyc)&&(nread == 0)&&(cfg_len>0)&&(~cfg_wp)
&&((~cfg_on_dev_trigger)
||(i_dev_ints[cfg_dev_trigger])))
begin // Initiate a read cycle
o_mwb_cyc <= 1'b1;
o_mwb_stb <= 1'b1;
o_mwb_we <= 1'b0;
o_mwb_addr<= cfg_raddr;
nwritten <= 0;
nread <= 0;
nacks <= 0;
end else begin
o_mwb_cyc <= 1'b0;
o_mwb_stb <= 1'b0;
o_mwb_we <= 1'b0;
o_mwb_addr <= cfg_raddr;
o_interrupt<= 1'b0;
nwritten <= 0;
if ((i_swb_cyc)&&(i_swb_stb)&&(i_swb_we))
begin
cfg_wp <= 1'b1;
case(i_swb_addr)
2'b00: begin
cfg_wp <= (i_swb_data[27:16]!=12'hfed);
cfg_blocklen_sub_one
<= i_swb_data[(LGMEMLEN-1):0]
+ {(LGMEMLEN){1'b1}};
// i.e. -1;
cfg_dev_trigger <= i_swb_data[14:10];
cfg_on_dev_trigger <= i_swb_data[15];
cfg_incs <= ~i_swb_data[29];
cfg_incd <= ~i_swb_data[28];
cfg_err <= 1'b0;
end
2'b01: cfg_len <= i_swb_data[(AW-1):0];
2'b10: cfg_raddr <= i_swb_data[(AW-1):0];
2'b11: cfg_waddr <= i_swb_data[(AW-1):0];
endcase
end
end
 
if (abort)
dma_state <= `DMA_IDLE;
end
default:
dma_state <= `DMA_IDLE;
endcase
 
initial o_interrupt = 1'b0;
always @(posedge i_clk)
o_interrupt <= (dma_state == `DMA_WRITE_ACK)&&(i_mwb_ack)
&&(last_write_ack)
&&(cfg_len == {{(AW-1){1'b0}},1'b1});
 
initial cfg_err = 1'b0;
always @(posedge i_clk)
if (dma_state == `DMA_IDLE)
begin
if ((i_swb_cyc)&&(i_swb_stb)&&(i_swb_we)
&&(i_swb_addr==2'b00))
cfg_err <= 1'b0;
end else if (((i_mwb_err)&&(o_mwb_cyc))||(abort))
cfg_err <= 1'b1;
 
initial last_read_request = 1'b0;
always @(posedge i_clk)
if ((dma_state == `DMA_WAIT)||(dma_state == `DMA_READ_REQ))
begin
if ((~i_mwb_stall)&&(dma_state == `DMA_READ_REQ))
begin
last_read_request <=
(nracks + 1 == { 1'b0, cfg_blocklen_sub_one})
||(bus_nracks == cfg_len-2);
end else
last_read_request <=
(nracks== { 1'b0, cfg_blocklen_sub_one})
||(bus_nracks == cfg_len-1);
end else
last_read_request <= 1'b0;
 
initial last_read_ack = 1'b0;
always @(posedge i_clk)
if ((dma_state == `DMA_READ_REQ)||(dma_state == `DMA_READ_ACK))
begin
if (i_mwb_ack)
last_read_ack <= (nread+2 == nracks);
else
last_read_ack <= (nread+1 == nracks);
end else
last_read_ack <= 1'b0;
 
initial last_write_request = 1'b0;
always @(posedge i_clk)
if (dma_state == `DMA_PRE_WRITE)
last_write_request <= (nread <= 1);
else if (dma_state == `DMA_WRITE_REQ)
begin
if (i_mwb_stall)
last_write_request <= (nwritten >= nread-1);
else
last_write_request <= (nwritten >= nread-2);
end else
last_write_request <= 1'b0;
 
initial last_write_ack = 1'b0;
always @(posedge i_clk)
if((dma_state == `DMA_WRITE_REQ)||(dma_state == `DMA_WRITE_ACK))
begin
if (i_mwb_ack)
last_write_ack <= (nwacks+2 == nwritten);
else
last_write_ack <= (nwacks+1 == nwritten);
end else
last_write_ack <= 1'b0;
 
assign o_mwb_cyc = (dma_state == `DMA_READ_REQ)
||(dma_state == `DMA_READ_ACK)
||(dma_state == `DMA_WRITE_REQ)
||(dma_state == `DMA_WRITE_ACK);
 
assign o_mwb_stb = (dma_state == `DMA_READ_REQ)
||(dma_state == `DMA_WRITE_REQ);
 
assign o_mwb_we = (dma_state == `DMA_PRE_WRITE)
||(dma_state == `DMA_WRITE_REQ)
||(dma_state == `DMA_WRITE_ACK);
 
//
// This is tricky. In order for Vivado to consider dma_mem to be a
// proper memory, it must have a simple address fed into it. Hence
418,22 → 294,25
//
reg [(LGMEMLEN-1):0] rdaddr;
always @(posedge i_clk)
if((dma_state == `DMA_IDLE)||(dma_state == `DMA_WAIT)
||(dma_state == `DMA_WRITE_ACK))
rdaddr <= 0;
else if ((dma_state == `DMA_PRE_WRITE)
||((dma_state==`DMA_WRITE_REQ)&&(~i_mwb_stall)))
rdaddr <= rdaddr + {{(LGMEMLEN-1){1'b0}},1'b1};
if ((o_mwb_cyc)&&(o_mwb_we)&&(o_mwb_stb)&&(~i_mwb_stall))
// This would be the normal advance, save that we are
// already one ahead of nwritten
rdaddr <= rdaddr + 1; // {{(LGMEMLEN-1){1'b0}},1};
else if ((~o_mwb_cyc)&&(nread > 0)&&(~cfg_err))
// Here's where we do our extra advance
rdaddr <= nwritten[(LGMEMLEN-1):0]+1;
else if ((~o_mwb_cyc)||(~o_mwb_we))
rdaddr <= nwritten[(LGMEMLEN-1):0];
always @(posedge i_clk)
if ((dma_state != `DMA_WRITE_REQ)||(~i_mwb_stall))
if ((~o_mwb_cyc)||((o_mwb_we)&&(o_mwb_stb)&&(~i_mwb_stall)))
o_mwb_data <= dma_mem[rdaddr];
always @(posedge i_clk)
if((dma_state == `DMA_READ_REQ)||(dma_state == `DMA_READ_ACK))
if ((o_mwb_cyc)&&(~o_mwb_we)&&(i_mwb_ack))
dma_mem[nread[(LGMEMLEN-1):0]] <= i_mwb_data;
 
always @(posedge i_clk)
casez(i_swb_addr)
2'b00: o_swb_data <= { (dma_state != `DMA_IDLE), cfg_err,
2'b00: o_swb_data <= { ~cfg_wp, cfg_err,
~cfg_incs, ~cfg_incd,
1'b0, nread,
cfg_on_dev_trigger, cfg_dev_trigger,
444,28 → 323,14
2'b11: o_swb_data <= { {(DW-AW){1'b0}}, cfg_waddr};
endcase
 
// This causes us to wait a minimum of two clocks before starting: One
// to go into the wait state, and then one while in the wait state to
// develop the trigger.
initial trigger = 1'b0;
always @(posedge i_clk)
trigger <= (dma_state == `DMA_WAIT)
&&((~cfg_on_dev_trigger)
||(i_dev_ints[cfg_dev_trigger]));
if ((i_swb_cyc)&&(i_swb_stb)) // &&(~i_swb_we))
o_swb_ack <= 1'b1;
// else if ((i_swb_cyc)&&(i_swb_stb)&&(i_swb_we)&&(~o_mwb_cyc)&&(nread == 0))
else
o_swb_ack <= 1'b0;
 
// Ack any access. We'll quietly ignore any access where we are busy,
// but ack it anyway. In other words, before writing to the device,
// double check that it isn't busy, and then write.
always @(posedge i_clk)
o_swb_ack <= (i_swb_cyc)&&(i_swb_stb);
 
assign o_swb_stall = 1'b0;
 
initial abort = 1'b0;
always @(posedge i_clk)
abort <= (i_rst)||((i_swb_cyc)&&(i_swb_stb)&&(i_swb_we)
&&(i_swb_addr == 2'b00)
&&(i_swb_data == 32'hffed0000));
 
endmodule
 
/zipcounter.v
27,7 → 27,7
//
///////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
// Copyright (C) 2015, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
61,13 → 61,17
// Interrupt line
output reg o_int;
 
initial o_int = 0;
initial o_wb_data = 32'h00;
always @(posedge i_clk)
if ((i_wb_cyc)&&(i_wb_stb)&&(i_wb_we))
{ o_int, o_wb_data } <= { 1'b0, i_wb_data };
o_wb_data <= i_wb_data;
else if (i_ce)
{ o_int, o_wb_data } <= o_wb_data+{{(BW-1){1'b0}},1'b1};
o_wb_data <= o_wb_data + 1;
 
initial o_int = 0;
always @(posedge i_clk)
if (i_ce)
o_int <= &o_wb_data;
else
o_int <= 1'b0;
 
/zipjiffies.v
45,7 → 45,7
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
// Copyright (C) 2015, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
67,7 → 67,7
i_wb_cyc, i_wb_stb, i_wb_we, i_wb_data,
o_wb_ack, o_wb_stall, o_wb_data,
o_int);
parameter BW = 32;
parameter BW = 32, VW = (BW-2);
input i_clk, i_ce;
// Wishbone inputs
input i_wb_cyc, i_wb_stb, i_wb_we;
104,13 → 104,13
 
initial new_set = 1'b0;
always @(posedge i_clk)
begin
// Delay things by a clock to simplify our logic
new_set <= ((i_wb_cyc)&&(i_wb_stb)&&(i_wb_we));
// new_when is a don't care when new_set = 0, so don't worry
// about setting it at all times.
new_when<= i_wb_data;
end
if ((i_wb_cyc)&&(i_wb_stb)&&(i_wb_we))
begin
new_set <= 1'b1;
new_when<= i_wb_data;
end else
new_set <= 1'b0;
 
initial o_int = 1'b0;
initial int_set = 1'b0;
118,18 → 118,16
begin
o_int <= 1'b0;
if ((i_ce)&&(int_set)&&(r_counter == int_when))
// Interrupts are self-clearing
o_int <= 1'b1; // Set the interrupt flag for one clock
else if ((new_set)&&(till_wb <= 0))
o_int <= 1'b1;
begin // Interrupts are self-clearing
o_int <= 1'b1; // Set the interrupt flag
int_set <= 1'b0;// Clear the interrupt
end
 
if ((new_set)&&(till_wb > 0))
int_set <= 1'b1;
else if ((i_ce)&&(r_counter == int_when))
int_set <= 1'b0;
 
if ((new_set)&&(till_wb > 0)&&((till_wb<till_when)||(~int_set)))
begin
int_when <= new_when;
int_set <= ((int_set)||(till_wb>0));
end
end
 
//

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.