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 |
|
// |