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

Subversion Repositories openarty

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /openarty/trunk/rtl
    from Rev 33 to Rev 34
    Reverse comparison

Rev 33 → Rev 34

/bigadd.v
36,31 → 36,55
//
//
module bigadd(i_clk, i_sync, i_a, i_b, o_r, o_sync);
parameter NCLOCKS = 1;
input i_clk, i_sync;
input [63:0] i_a, i_b;
output reg [63:0] o_r;
output reg o_sync;
output wire [63:0] o_r;
output wire o_sync;
 
reg r_sync, r_pps;
reg [31:0] r_hi_a, r_hi_b, r_low;
generate
if (NCLOCKS == 0)
begin
assign o_sync= i_sync;
assign o_r = i_a + i_b;
end else if (NCLOCKS == 1)
begin
reg r_sync;
reg [63:0] r_out;
always @(posedge i_clk)
r_sync <= i_sync;
always @(posedge i_clk)
r_out <= i_a+i_b;
 
initial r_sync = 1'b0;
always @(posedge i_clk)
r_sync <= i_sync;
assign o_sync = r_sync;
assign o_r = r_out;
end else // if (NCLOCKS == 2)
begin
reg r_sync, r_pps;
reg [31:0] r_hi, r_low;
 
always @(posedge i_clk)
{ r_pps, r_low } <= i_a[31:0] + i_b[31:0];
always @(posedge i_clk)
r_hi_a <= i_a[63:32];
always @(posedge i_clk)
r_hi_b <= i_b[63:32];
reg f_sync;
reg [63:0] f_r;
 
initial o_sync = 1'b0;
always @(posedge i_clk)
o_sync <= r_sync;
always @(posedge i_clk)
o_r[31:0] <= r_low;
always @(posedge i_clk)
o_r[63:32] <= r_hi_a + r_hi_b + { 31'h00, r_pps };
initial r_sync = 1'b0;
always @(posedge i_clk)
r_sync <= i_sync;
 
always @(posedge i_clk)
{ r_pps, r_low } <= i_a[31:0] + i_b[31:0];
always @(posedge i_clk)
r_hi <= i_a[63:32] + i_b[63:32];
 
initial f_sync = 1'b0;
always @(posedge i_clk)
f_sync <= r_sync;
always @(posedge i_clk)
f_r[31:0] <= r_low;
always @(posedge i_clk)
f_r[63:32] <= r_hi + { 31'h00, r_pps };
 
assign o_sync = f_sync;
assign o_r = f_r;
end endgenerate
 
endmodule
/bigsmpy.v
4,8 → 4,16
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose:
// Purpose: To multiply two 32-bit numbers into a 64-bit number. We try
// to use the hardware multiply to do this, but just what kind of
// hardware multiply is actually available ... can be used to determine
// how many clocks to take.
//
// If you look at the algorithm below, it's actually a series of a couple
// of independent algorithms dependent upon the parameter NCLOCKS. If your
// timing through here becomes a problem, set NCLOCKS to a higher number
// and see if that doesn't help things.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
36,7 → 44,7
//
//
module bigsmpy(i_clk, i_sync, i_sgn, i_a, i_b, o_r, o_sync);
parameter CLOCKS = 1;
parameter NCLOCKS = 1;
input i_clk, i_sync, i_sgn;
input [31:0] i_a, i_b;
output reg [63:0] o_r;
43,7 → 51,7
output reg o_sync;
 
generate
if (CLOCKS == 1)
if (NCLOCKS == 1)
begin
wire signed [31:0] w_sa, w_sb;
wire [31:0] w_ua, w_ub;
62,15 → 70,18
o_r <= w_ua * w_ub;
end
 
end else if (CLOCKS == 2)
end else if (NCLOCKS == 2)
begin
reg r_sync;
reg signed [31:0] r_sa, r_sb;
wire [31:0] w_ua, w_ub;
 
initial r_sync = 1'b0;
always @(posedge i_clk)
begin
r_sa = i_a;
r_sb = i_b;
r_sync <=i_sync;
r_sa <= i_a;
r_sb <= i_b;
end
 
assign w_ua = r_sa;
78,7 → 89,7
 
always @(posedge i_clk)
begin
o_sync <= i_sync;
o_sync <= r_sync;
if (i_sgn)
o_r <= r_sa * r_sb;
else
86,7 → 97,7
end
 
end else if (CLOCKS == 5)
end else if (NCLOCKS == 5)
begin
//
// A pipeline, shift register, to track our
/bigsub.v
4,8 → 4,15
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose:
// Purpose: To subtract two 64-bit numbers, while maintaining
// synchronization to whatever purpose these numbers had
// originally. For this reason, there is an i_sync input and an o_sync
// output. If i_sync is true with a particular set of data, o_sync will
// then be true when that data is placed on the output.
//
// If we needed to slow this down even more, I suppose we could register
// the inputs before we used them ...
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
36,31 → 43,60
//
//
module bigsub(i_clk, i_sync, i_a, i_b, o_r, o_sync);
parameter NCLOCKS = 1;
input i_clk, i_sync;
input [63:0] i_a, i_b;
output reg [63:0] o_r;
output reg o_sync;
output wire [63:0] o_r;
output wire o_sync;
 
reg r_sync, r_pps;
reg [31:0] r_hi_a, r_hi_b, r_low;
generate
if (NCLOCKS == 0)
begin
assign o_sync= i_sync;
assign o_r = i_a - i_b;
end else if (NCLOCKS == 1)
begin
reg r_sync;
reg [63:0] r_out;
always @(posedge i_clk)
r_sync <= i_sync;
always @(posedge i_clk)
r_out <= i_a - i_b;
 
initial r_sync = 1'b0;
always @(posedge i_clk)
r_sync <= i_sync;
assign o_sync = r_sync;
assign o_r = r_out;
end else // if (NCLOCKS == 2)
begin
reg r_sync, r_pps;
reg [31:0] r_hi, r_low;
 
always @(posedge i_clk)
{ r_pps, r_low } <= i_a[31:0] + ({1'b1,~i_b[31:0]}) + 1'b1;
always @(posedge i_clk)
r_hi_a <= i_a[63:32];
always @(posedge i_clk)
r_hi_b <= ~i_b[63:32];
reg [63:0] f_r;
reg f_sync;
 
initial o_sync = 1'b0;
always @(posedge i_clk)
o_sync <= r_sync;
always @(posedge i_clk)
o_r[31:0] <= r_low;
always @(posedge i_clk)
o_r[63:32] <= r_hi_a + r_hi_b + { 31'h00, r_pps };
wire [63:0] i_b_n;
assign i_b_n = ~i_b;
 
initial r_sync = 1'b0;
always @(posedge i_clk)
r_sync <= i_sync;
 
always @(posedge i_clk)
{ r_pps, r_low } <= i_a[31:0] + i_b_n[31:0] + 1'b1;
always @(posedge i_clk)
r_hi <= i_a[63:32] + i_b_n[63:32];
 
initial f_sync = 1'b0;
always @(posedge i_clk)
f_sync <= r_sync;
always @(posedge i_clk)
f_r[31:0] <= r_low;
always @(posedge i_clk)
f_r[63:32] <= r_hi + { 31'h00, r_pps };
 
assign o_sync = f_sync;
assign o_r = f_r;
 
end endgenerate
 
endmodule
 
/builddate.v
38,4 → 38,4
////////////////////////////////////////////////////////////////////////////////
//
//
`define DATESTAMP 32'h20161018
`define DATESTAMP 32'h20161024
/busmaster.v
50,6 → 50,9
`define FLASH_ACCESS
`define SDRAM_ACCESS
`define GPS_CLOCK
`ifdef VERILATOR
`define GPSTB
`endif
// UART_ACCESS and GPS_UART have both been placed within fastio
// `define UART_ACCESS
// `define GPS_UART
656,8 → 659,8
wire [3:0] w_led;
wire rtc_ppd;
fastio #(
.AUXUART_SETUP(30'hd705), // 115200 Baud, 8N1, from 81.25M
.GPSUART_SETUP(30'hd8464), // 9600 Baud, 8N1
.AUXUART_SETUP(30'd705), // 115200 Baud, 8N1, from 81.25M
.GPSUART_SETUP(30'd8464), // 9600 Baud, 8N1
.EXTRACLOCK(0)
) runio(i_clk, i_sw, i_btn,
w_led, o_clr_led0, o_clr_led1, o_clr_led2, o_clr_led3,
665,7 → 668,7
wb_cyc, (io_sel)&&(wb_stb), wb_we, wb_addr[4:0],
wb_data, io_ack, io_stall, io_data,
rtc_ppd,
bus_err_addr, master_ints, w_interrupt,
bus_err_addr, gps_now[63:32], gps_step[47:16], master_ints, w_interrupt,
board_ints);
assign { gpio_int, auxrx_int, auxtx_int, gpsrx_int, sw_int, btn_int } = board_ints;
 
/enetctrl.v
49,7 → 49,8
o_wb_ack, o_wb_stall, o_wb_data,
o_mdclk, o_mdio, i_mdio, o_mdwe,
o_debug);
parameter CLKBITS=3; // = 3 for 200MHz source clock, 2 for 100 MHz
parameter CLKBITS=3, // = 3 for 200MHz source clock, 2 for 100 MHz
PHYADDR = 5'h01;
input i_clk, i_rst;
input i_wb_cyc, i_wb_stb, i_wb_we;
input [4:0] i_wb_addr;
63,9 → 64,7
//
output wire [31:0] o_debug;
//
parameter PHYADDR = 5'h01;
 
 
reg read_pending, write_pending;
reg [4:0] r_addr;
reg [15:0] read_reg, write_reg, r_data;
/fastio.v
43,15 → 43,18
o_clr_led0, o_clr_led1, o_clr_led2, o_clr_led3,
// Board level PMod I/O
i_aux_rx, o_aux_tx, o_aux_cts, i_gps_rx, o_gps_tx,
// i_gpio, o_gpio,
`ifdef USE_GPIO
i_gpio, o_gpio,
`endif
// Wishbone control
i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr,
i_wb_data, o_wb_ack, o_wb_stall, o_wb_data,
// Cross-board I/O
i_rtc_ppd, i_buserr, i_other_ints, o_bus_int, o_board_ints);
i_rtc_ppd, i_buserr, i_gps_now, i_gps_step, i_other_ints, o_bus_int, o_board_ints);
parameter AUXUART_SETUP = 30'd1736, // 115200 baud from 200MHz clk
GPSUART_SETUP = 30'd20833, // 9600 baud from 200MHz clk
EXTRACLOCK = 1; // Do we need an extra clock to process?
EXTRACLOCK = 1, // Do we need an extra clock to process?
NGPI=0, NGPO=0; // Number of GPIO in and out wires
input i_clk;
// Board level I/O
input [3:0] i_sw;
71,9 → 74,11
input i_gps_rx;
output wire o_gps_tx;
//
`ifdef USE_GPIO
// GPIO
// input [(NGPI-1):0] i_gpio;
// output reg [(NGPO-1):0] o_gpio;
input [(NGPI-1):0] i_gpio;
output reg [(NGPO-1):0] o_gpio;
`endif
//
// Wishbone inputs
input i_wb_cyc, i_wb_stb, i_wb_we;
87,6 → 92,8
input i_rtc_ppd;
// Address of the last bus error
input [31:0] i_buserr;
// The current time, as produced by the GPS tracking processor
input [31:0] i_gps_now, i_gps_step;
//
// Interrupts -- both the output bus interrupt, as well as those
// internally generated interrupts which may be used elsewhere
151,7 → 158,10
reg [31:0] pwr_counter;
initial pwr_counter = 32'h00;
always @(posedge i_clk)
pwr_counter <= pwr_counter+32'h001;
if (pwr_counter[31])
pwr_counter[30:0] <= pwr_counter[30:0] + 31'h001;
else
pwr_counter[31:0] <= pwr_counter[31:0] + 31'h001;
 
//
// BTNSW
207,7 → 217,15
// when any of the inputs changes. (Sorry, which input isn't (yet)
// selectable.)
//
wire [31:0] gpio_data;
`ifdef USE_GPIO
wbgpio #(NIN, NOUT)
gpioi(i_clk, w_wb_cyc, (w_wb_stb)&&(w_wb_addr == 5'hd), 1'b1,
w_wb_data, gpio_data, i_gpio, o_gpio, gpio_int);
`else
assign gpio_data = 32'h00;
assign gpio_int = 1'b0;
`endif
 
//
// AUX (UART) SETUP
416,7 → 434,7
end
always @(posedge i_clk)
if(((i_wb_stb)&&(~i_wb_we)&&(i_wb_addr == 5'h10))||(gpsrx_stb))
r_gpsrx_data[8] <= gpsrx_stb;
r_gpsrx_data[8] <= !gpsrx_stb;
assign gpsrx_data = { 20'h00, r_gpsrx_data };
assign gpsrx_int = r_gpsrx_data[8];
 
459,11 → 477,13
5'h0a: o_wb_data <= w_clr_led2;
5'h0b: o_wb_data <= w_clr_led3;
5'h0c: o_wb_data <= date_data;
// 5'h0d: o_wb_data <= gpio_data;
5'h0d: o_wb_data <= gpio_data;
5'h0e: o_wb_data <= auxrx_data;
5'h0f: o_wb_data <= auxtx_data;
5'h10: o_wb_data <= gpsrx_data;
5'h11: o_wb_data <= gpstx_data;
5'h12: o_wb_data <= i_gps_now;
5'h13: o_wb_data <= i_gps_step;
// 5'hf: UART_SETUP
// 4'h6: GPIO
// ?? : GPS-UARTRX
/gpsclock.v
98,6 → 98,10
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
// `define DEBUG
//
module gpsclock(i_clk, i_rst, i_pps, o_pps, o_led,
i_wb_cyc_stb, i_wb_we, i_wb_addr, i_wb_data,
o_wb_ack, o_wb_stall, o_wb_data,
149,7 → 153,8
// our data is valid during those handful.
//
// Timing
reg err_tick, mpy_aux, mpy_sync_two, delay_step_clk;
reg err_tick, shift_tick, config_tick, mpy_aux, mpy_sync_two,
delay_step_clk, step_carry_tick;
wire sub_tick, fltr_tick;
 
//
162,7 → 167,10
// an earlier clock.
//
// Tracking
reg [(RW-1):0] count_correction, pre_count_correction;
reg config_filter_errors;
reg [(RW-1):0] pre_count_correction, r_count_correction,
r_filtered_err;
wire [(RW-1):0] count_correction;
reg [(HRW-1):0] step_correction;
reg [(HRW-1):0] delayed_step_correction, delayed_step;
reg signed [(HRW-1):0] mpy_input;
178,8 → 186,12
//
//
//
// DEFAULT_STEP = 64'h0000_0034_dc73_67da, // 2^64 / 100 MHz
// 28'h34d_c736 << 8, and hence we have 32'h834d_c736
// DEFAULT_STEP = 64'h0000_0034_dc73_67da, // 2^64 / 81.25 MHz
// = 28'hd371cd9 << (20-10), and hence we have 32'had37_1cd9
// Other useful values:
// 32'had6bf94d // 80MHz
// 32'haabcc771 // 100MHz
// 32'hbd669d0e // 160.5MHz
initial r_def_step = DEFAULT_STEP;
always @(posedge i_clk)
pre_step <= { 16'h00,
191,6 → 203,8
reg wb_write;
reg [1:0] r_wb_addr;
reg [31:0] r_wb_data;
reg [7:0] lost_ticks;
initial lost_ticks = 0;
always @(posedge i_clk)
wb_write <= (i_wb_cyc_stb)&&(i_wb_we);
always @(posedge i_clk)
200,13 → 214,20
assign wb_data = r_wb_data;
assign wb_addr = r_wb_addr;
 
initial config_filter_errors = 1'b1;
initial r_alpha = 6'h2;
initial r_beta = 32'h14bda12f;
initial r_gamma = 32'h1f533ae8;
initial new_config = 1'b0;
always @(posedge i_clk)
if (wb_write)
begin
new_config = 1'b1;
new_config <= 1'b1;
case(wb_addr)
2'b00: r_alpha <= wb_data[5:0];
2'b00: begin
r_alpha <= wb_data[5:0];
config_filter_errors <= (wb_data[5:0] != 6'h0);
end
2'b01: r_beta <= wb_data;
2'b10: r_gamma <= wb_data;
2'b11: r_def_step <= wb_data;
214,10 → 235,10
// r_defstep <= i_wb_data;
endcase
end else
new_config = 1'b0;
new_config <= 1'b0;
always @(posedge i_clk)
case (i_wb_addr)
2'b00: o_wb_data <= { 26'h00, r_alpha };
2'b00: o_wb_data <= { lost_ticks, 18'h00, r_alpha };
2'b01: o_wb_data <= r_beta;
2'b10: o_wb_data <= r_gamma;
2'b11: o_wb_data <= r_def_step;
241,7 → 262,7
//
//
always @(posedge i_clk)
begin
begin // This will delay our resulting time by a known 2 clock ticks
pps_d <= i_pps;
ck_pps <= pps_d;
lst_pps <= ck_pps;
248,25 → 269,41
end
 
// Provide a touch of debounce protection ... equal to about
// one quarter of a second.
reg [(RW-3):0] tick_enable_counter;
wire [(RW-1):0] w_tick_enable_sum;
wire w_tick_enable, w_tick_enable_unused;
bigadd enabler(i_clk, 1'b0, o_step, { 2'b0, tick_enable_counter },
w_tick_enable_sum, w_tick_enable_unused);
// one quarter of a second. This is a coarse predictor, however,
// since it uses only the top 32-bits of the step.
//
// Here's the idea: on any tick, we start a 32-bit counter, stepping
// unevenly by o_step[61:30] at each tick. Once the counter crosses
// zero, we stop counting and we enable the clock tick. Since the
// counter should overflow 4x per second (assuming our clock rate is
// less than 16GHz), we should be good to go. Oh, and we also round
// our step up by one ... to guarantee that we always end earlier than
// designed, rather than ever later.
//
wire w_tick_enable;
reg [31:0] tick_enable_counter;
reg tick_enable_carry;
initial tick_enable_carry = 0;
initial tick_enable_counter = 0;
always @(posedge i_clk)
begin
if (tick)
tick_enable_counter <= 0;
else if (|w_tick_enable_sum[(RW-1):(RW-2)])
tick_enable_counter <= {(RW-2){1'b1}};
if ((ck_pps)&&(~lst_pps))
{ tick_enable_carry, tick_enable_counter } <= 0;
else if (tick_enable_carry)
tick_enable_counter <= 32'hffff_ffff;
else
tick_enable_counter <= w_tick_enable_sum[(RW-3):0];
{tick_enable_carry, tick_enable_counter}
<= o_step[(RW-3):(RW-34)]
+ tick_enable_counter + 1'b1;
end
assign w_tick_enable = tick_enable_counter[(RW-3)];
assign w_tick_enable = tick_enable_carry;
 
assign tick= (ck_pps)&&(~lst_pps)&&(w_tick_enable);
always @(posedge i_clk)
if (wb_write)
lost_ticks <= 8'h00;
else if ((ck_pps)&&(~lst_pps)&&(!w_tick_enable))
lost_ticks <= lost_ticks+1'b1;
assign o_dbg[0] = tick;
assign o_dbg[1] = w_tick_enable;
 
277,17 → 314,53
// of the second if we are in tracking mode. The 'o_pps' signal is
// generated from the carry/overflow of the o_count addition.
//
// The output of this loop, both o_pps and o_count, is the current
// subsecond time as determined by this clock.
//
//
reg cnt_carry;
reg [31:0] p_count;
initial o_count = 0;
initial o_pps = 1'b0;
always @(posedge i_clk)
`ifndef USE_THE_OLD_CODE
begin
// Very simple: we add the count correction, which is given by
// a pre-determined sum of the step and any error, to our
// "count" at every clock tick. If this ever overflows, the
// overflow or carry is our PPS signal. Unlike the last time
// we built this logic, here we acknowledge that the count
// correction can never be negative. As a result, we have no
// o_pps suppression.
{ cnt_carry, p_count } <= p_count[31:0] + r_count_correction[31:0];
{ o_pps, o_count[63:32] } <= o_count[63:32]
+ r_count_correction[63:32]
+ { 31'h00, cnt_carry };
if (r_count_correction[(RW-1)])
o_pps <= 1'b0;
// Delay the bottom bits of o_count by one clock, so that they
// now match up with the top bits.
o_count[31:0] <= p_count;
end
`else
if ((o_tracking)&&(tick))
begin
{ cnt_carry, p_count } <= p_count[31:0] + count_correction[31:0];
// Save the carry to be applied at the next clock, so
// that we never have to do more than a 32-bit add.
// (well, okay, a 33-bit add ...)
//
// The count_correction value here is really our step,
// plus a value determined from our filter loop.
{ cnt_carry, p_count }
<= p_count[31:0] + count_correction[31:0];
//
// On the second clock, we add the high order bits
// together, and possibly get a carry. We use this
// carry as our o_pps output.
if (~count_correction[(RW-1)])
begin
// Here, we need to correct by jumping forward.
//
// Note that we don't create an o_pps just
// because the gps_pps states that there should
// be one. Instead, we hold to the normal
294,14 → 367,19
// means of business. At the tick, however,
// we add both the step and the correction to
// the current count.
{ o_pps, o_count[63:32] } <= o_count[63:32] +count_correction[63:32]+ { 31'h00, cnt_carry };
{ o_pps, o_count[63:32] } <= o_count[63:32]
+ count_correction[63:32]
+ { 31'h00, cnt_carry };
end else begin
// If the count correction is negative, it means
// we need to go backwards. In this case,
// there shouldn't be any o_pps, least we get
// two of them.
// two of them. So ... we skip an output PPS,
// knowing the correct PPS is coming next.
o_pps <= 1'b0;
o_count[63:32] <= o_count[63:32] + count_correction[63:32];
o_count[63:32] <= o_count[63:32]
+ count_correction[63:32]
+ { 31'h00, cnt_carry };
end
end else begin
// The difference between count_correction and
310,15 → 388,44
// correction. Likewise, even if we are, we only
// want to use it on the ticks.
{ cnt_carry, p_count } <= p_count + o_step[31:0];
{ o_pps, o_count[63:32] } <= o_count[63:32] + o_step[63:32];
{ o_pps, o_count[63:32] } <= o_count[63:32]
+ o_step[63:32]
+ { 31'h00, cnt_carry};
end
 
// Here we delay the bottom bits of o_count by one clock, so that they
// now match up with the top bits.
always @(posedge i_clk)
o_count[31:0] <= p_count;
`endif
 
 
 
//
// The step
//
// The counter above is only as good as the step size given to it.
// Here, we work with that step size, and apply a correction based
// upon the last tick. The idea in the step correction is that we
// wish to add this step correction to our step amount. We have one
// clock tick (i.e. one second) from when we make our error measurement
// until we must apply the correction.
//
// The correction, calculated far below, will be placed into the value
//
// step_correction
//
// We just need to figure out what the new step will be here, given
// that correction.
//
reg [(HRW):0] step_correction_plus_carry;
always @(posedge i_clk)
step_correction_plus_carry = step_correction + { 31'h00, delayed_carry };
if (step_carry_tick)
step_correction_plus_carry
<= { step_correction[(HRW-1)],step_correction }
+ { 32'h00, delayed_carry };
 
 
wire w_step_correct_unused;
wire [(RW-1):0] new_step;
bigadd getnewstep(i_clk, 1'b0, o_step,
328,17 → 435,23
 
reg delayed_carry;
initial delayed_carry = 0;
initial o_step = 64'h002af31dc461;
 
wire [31:0] initial_default_step = DEFAULT_STEP;
// initial o_step = 64'h002af31dc461; // 100MHz
initial o_step = { 16'h00, (({ initial_default_step[27:0], 20'h00 })
>> initial_default_step[31:28])};
always @(posedge i_clk)
if ((i_rst)||(dly_config))
o_step <= pre_step;
`ifndef DEBUG
else if ((o_tracking) && (tick))
o_step <= new_step;
o_step <= new_step;
`endif
 
initial delayed_step = 0;
always @(posedge i_clk)
if ((i_rst)||(dly_config))
delayed_step <= 0;
{ delayed_carry, delayed_step } <= 0;
else if (delay_step_clk)
{ delayed_carry, delayed_step } <= delayed_step
+ delayed_step_correction;
360,15 → 473,44
// and is near zero, the o_err is then the negation of this when the
// tick does show up.
//
 
// Note that our measured error, o_err, will be valid one tick *after*
// the top of the second tick (tick).
//
// ONE_SECOND in this equation is set to 2^64, or zero during
// implementation. This makes the 64-bit subtract ... doable.
initial o_err = 0;
always @(posedge i_clk)
if (tick)
o_err <= ONE_SECOND - o_count;
 
// Because o_err is delayed one clock from the tick, we create a strobe
// capturing when the error is valid.
initial err_tick = 1'b0;
always @(posedge i_clk)
err_tick <= tick;
 
//
// We are now going to filter this error, via:
//
// filtered_err <= o_err>>r_alpha + (1-1>>r_alpha)*filtered_err
//
// This implements a very simple recursive averager.
//
// You may not recognize it below, though, since we have simplified the
// equation into:
//
// filtered_err <= filtered_err + (o_err - filtered_err)>>r_alpha
//
 
// On some architectures, adding and subtracting 64'bit number cannot
// be done in a single clock tick. On these architectures, we may
// take a couple clocks. Here, the "bigsub" module captures what it
// takes to subtract 64-bit numbers.
//
// Either way, here we subtract our error from our filtered_err. This
// is the first step of the recursive average--figuring out what value
// we are going to apply to the recursive average.
bigsub suberri(i_clk, err_tick, o_err,
filtered_err, filter_sub_count, sub_tick);
 
378,67 → 520,148
// Why is because Verilator decides that these values are unsigned,
// and so despite being told that they are signed values, verilator
// doesn't sign extend them upon shifting. Put together,
// { shift_hi[low-bits], shift_lo[low-bits] } make up a full RW
// { shift_hi[low-bits], shift_lo[low-bits] } make up a full RW (i.e.64)
// bit correction factor.
reg signed [(RW-1):0] shift_hi, shift_lo;
always @(posedge i_clk)
begin
shift_hi <= { {(HRW){filter_sub_count[(RW-1)]}},
shift_tick<= sub_tick;
 
// Because we do our add (below) on *every* clock tick, we must
// make certain that the value we add to it is only non-zero
// on one clock tick. Hence, we wait for sub_tick to be true,
// set the value, and otherwise keep it clear.
if (sub_tick)
begin
shift_hi <= { {(HRW){filter_sub_count[(RW-1)]}},
filter_sub_count[(RW-1):HRW] }>>r_alpha;
shift_lo <= filter_sub_count[(RW-1):0]>>r_alpha;
shift_lo <= filter_sub_count[(RW-1):0]>>r_alpha;
end else begin
shift_hi <= 0;
shift_lo <= 0;
end
end
 
bigadd adderr(i_clk, sub_tick, filtered_err,
// You may notice, it's now been several clocks since the top of the
// second. Still, filtered_err hasn't changed. It only changes once
// a second based upon the results of these computations. Here we take
// another clock (or two) to figure out the next step in our algorithm.
bigadd adderr(i_clk, shift_tick, r_filtered_err,
{ shift_hi[(HRW-1):0], shift_lo[(HRW-1):0] },
filtered_err, fltr_tick);
/*
 
always @(posedge i_clk)
if ((o_tracking)&&(sub_tick))
filtered_err<= filtered_err
+ { shift_hi[(HRW-1):0], shift_lo[(HRW-1):0] };
*/
if (fltr_tick)
r_filtered_err <= filtered_err;
else if ((dly_config)||(!o_tracking))
r_filtered_err <= 0;
 
reg [(RW-1):0] r_mpy_err;
always @(posedge i_clk)
if (fltr_tick)
if (err_tick)
r_mpy_err <= (config_filter_errors) ? r_filtered_err : o_err;
always @(posedge i_clk)
config_tick <= err_tick;
 
// Okay, so we've gone from our original tick to the err_tick, the
// sub_tick, the shift_tick, and now the fltr_tick.
//
// We want to multiply our filtered error by one of two constants.
// Here, we set up those constants. We use the fltr_tick as a strobe,
// but also to select one particular constant. When the multiply comes
// back, and the strobe is true, we'll know that the constant going
// in with the strobe on (r_beta) corresponds to the product coming out,
// and that the second product we need will be on the next clock.
always @(posedge i_clk)
if (err_tick)
mpy_input <= r_beta;
else
mpy_input <= r_gamma;
always @(posedge i_clk)
mpy_aux <= fltr_tick;
mpy_aux <= err_tick;
 
//
// The multiply
//
// Remember, we take our filtered error and multiply it by a constant
// to determine our step correction and another constant to determine
// our count correction? We'll ... here's that multiply.
//
wire mpy_sync;
wire [(RW-1):0] mpy_out;
initial mpy_sync_two = 1'b0;
// Sign extend all inputs to RW bits
wire signed [(RW-1):0] w_mpy_input, w_mpy_err;
assign w_mpy_input = { {(RW-DW){mpy_input[(DW-1)]}}, mpy_input[(DW-1):0]};
assign w_mpy_err = { {(RW-NPW){filtered_err[(RW-1)]}}, filtered_err[(RW-1):(RW-NPW)]};
bigsmpy mpyi(i_clk, mpy_aux, 1'b1, w_mpy_input[31:0], w_mpy_err[31:0],
mpy_out, mpy_sync);
assign w_mpy_input = { {(RW-DW){mpy_input[(DW-1)]}},
mpy_input[(DW-1):0]};
assign w_mpy_err = { {(RW-NPW){r_mpy_err[(RW-1)]}},
r_mpy_err[(RW-1):(RW-NPW)]};
//
// Here's our big multiply.
//
bigsmpy #(.NCLOCKS(1))
mpyi(i_clk, mpy_aux, 1'b1, w_mpy_input[31:0], w_mpy_err[31:0],
w_mpy_out, mpy_sync);
 
// We use this to grab the second product from the multiply. This
// second product is true the clock after mpy_sync is high, so we
// just do a simple delay to get this strobe logic.
always @(posedge i_clk)
mpy_sync_two <= mpy_sync;
assign w_mpy_out = mpy_out;
 
 
// The post-multiply
//
// Remember, the mpy_sync line coming out of the multiply will be true
// when the product of the error and i_beta comes out.
//
initial pre_count_correction = 0;
initial step_correction = 0;
initial delayed_step_correction = 0;
always @(posedge i_clk)
if (mpy_sync)
if (mpy_sync) // i_beta product
pre_count_correction <= w_mpy_out;
else if (mpy_sync_two) begin
always @(posedge i_clk)
if (mpy_sync_two) begin // i_gamma product
step_correction <= w_mpy_out[(RW-1):HRW];
delayed_step_correction <= w_mpy_out[(HRW-1):0];
end
 
`ifdef DEBUG
assign count_correction = o_step;
`else
// The correction for the number of counts in our counter is given
// by pre_count_correction. When we add this to the counter, we'll
// need to add the step to it as well. To help timing out with 64-bit
// math, let's do that step+correction math here, so that we can later
// do
// counts = counts + count_correction
// instead of
// counts = counts + step + pre_count_correction
// saves us one addition--especially since we have the clock to do this.
wire count_correction_strobe;
bigadd ccounts(i_clk, mpy_sync_two, o_step, pre_count_correction,
count_correction, count_correction_strobe);
 
// Our original plan was to apply this correction at the top of the
// second. The problem is that our loop filter math depends upon this
// correction being applied before the top of the second error gets
// measured. Hence, we'll apply it at some time mid-second, not
// long after the error is measured (w/in 16 clocks or so), and never
// notice the difference until the top of the next second where it
// now appears to have properly taken place.
always @(posedge i_clk)
count_correction <= pre_count_correction + o_step;
if (count_correction_strobe)
r_count_correction <= count_correction;
else
r_count_correction <= o_step;
`endif
 
initial delay_step_clk = 1'b0;
always @(posedge i_clk)
delay_step_clk <= mpy_sync_two;
initial step_carry_tick = 1'b0;
always @(posedge i_clk)
step_carry_tick <= delay_step_clk;
 
//
//
496,7 → 719,9
count_valid_ticks <= 3'h0;
initial o_tracking = 1'b0;
always @(posedge i_clk)
if ((tick)&&(&count_valid_ticks))
if (dly_config) // Break the tracking loop on a config change
o_tracking <= 1'b0;
else if ((tick)&&(&count_valid_ticks))
o_tracking <= 1'b1;
else if ((tick)||(count_valid_ticks == 0))
o_tracking <= 1'b0;
/gpsclock_tb.v
66,6 → 66,8
//
//
//
initial r_jump = 0;
initial r_maxcount = 32'd81200000;
always @(posedge i_clk)
if ((i_wb_cyc_stb)&&(i_wb_we))
begin
/lloled.v
4,8 → 4,27
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose:
// Purpose: This is a low-level SPI output (not input) controller
// designed to command interactions between an upper level
// controller and a PModOLEDrgb. As a result, this is a one-bit
// (traditional, not quad) SPI controller, it has no MISO input bits,
// and it also controls a DCN bits (output data at active high, vs
// output control at active low).
//
// This particular implementation was taken from a low-level QSPI
// controller. For those who wish to compare, the low-level QSPI
// controller is very similar to the low-level EQSPI controller that is
// also a part of the OpenArty project.
//
// Interfacing with the controller works as follows: If the controller
// is idle, set the values you wish to send and strobe the i_wr bit.
// Once the last bit has been committed to the interface, but before it
// closes the connection by setting CS_N high, it will check the i_wr bit
// again. If that bit is high, the busy bit will be dropped for one
// cycle, new data will be accepted, and the controller will continue
// with the new(er) data as though it was still part of the last
// transmission (without lowering cs_n).
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
39,6 → 58,7
`define OLED_READY 3'h3
`define OLED_STOP 3'h4
`define OLED_STOP_B 3'h5
`define OLED_STOP_C 3'h6
 
// Modes
`define OLED_MOD_SPI 2'b00
157,8 → 177,8
o_mosi <= r_word[31];
end else if (~last_counter)
begin
o_busy <= (pre_last_counter)&&(o_sck)
&&((state != `OLED_READY)||(~i_wr));
o_busy <= (!pre_last_counter)||(!o_sck)
||(state != `OLED_READY)||(~i_wr);
end else if (~o_sck)
begin
o_sck <= 1'b1;
205,12 → 225,22
o_sck <= 1'b1; // Stop the clock
o_busy <= 1'b1; // Still busy till port is clear
state <= `OLED_STOP_B;
end else // if (state == `OLED_STOP_B)
end else if (state == `OLED_STOP_B)
begin
o_cs_n <= 1'b1; // Deselect CS
o_sck <= 1'b1;
// Do I need this????
// spi_len <= 3; // Minimum CS high time before next cmd
state <= `OLED_STOP_C;
o_mosi <= 1'b1;
o_busy <= 1'b1;
end else // if (state == `OLED_STOP_C)
begin
// Keep us in idle for at least a full clock period.
o_cs_n <= 1'b1; // Deselect CS
o_sck <= 1'b1;
// Do I need this????
// spi_len <= 3; // Minimum CS high time before next cmd
state <= `OLED_IDLE;
o_mosi <= 1'b1;
o_busy <= 1'b1;
/wboled.v
4,8 → 4,113
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose:
// Purpose: To provide a *very* simplified controller for a PMod OLEDrgb.
// This controller implements four registers (described below),
// although it might feel like only two in practice. As with all of our
// other wishbone work, all transactions are 32-bits--even though, as an
// example, the data word for the device is only ever 16-bits long.
//
// The device control, outlined below, is also colored by two facts:
// 1. There is no means to read from the device. Sure, the chip on the
// PMod has a full read/write bus, but it hasn't been entirely
// wired to the PMod pins. This was probably done so that the
// interface could handle the paucity of pins available, but for
// whatever reason, there's no way to read from the device.
// 2. The device is controlled by a SPI port, but with an extra wire that
// determines whether or not you are writing to the control or the
// data port on the device. Hence the four wire SPI protocol has
// lost the MISO wire and gained a Data / Control (N) (or dcn)
// wire.
// 3. As implemented, the device also has two power control wires and a
// reset wire. The reset wire is negative logic. Without setting
// the PMOD-Enable wire high, the board has no power. The
// VCCEN pin is not to be set high without PMOD-Enable high.
// Finally, setting reset low (with PMod-Enable high), places the
// device into a reset condition.
//
// The design of the controller, as with the design of other controllers
// we have built, is focused around the design principles:
// 1. Use the bottom 23 bits of a word for the command, if possible.
// Such commands can be loaded into registers with simple LDI
// instructions. Even better, restrict any status results from the
// device to 18 bits, so that instructions that use immediates
// such as TEST #,Rx, can use these immediates.
// 2. Protect against inadvertant changes to the power port. For this,
// we insist that a minimum of two bits be high to change the
// power port bits, and that just reading from the port and
// writing back with a changed power bit is not sufficient to
// change the power.
// 3. Permit atomic changes to the individual power control bits,
// by outlining which exact bits change upon any write, and
// permitting only the bits specified to change.
// 4. Don't stall the bus. So, if a command comes in and the
// device is busy, we'll ignore the command. It is up to the
// user to make certain the device isn't fed faster than it is
// able. (Perhaps the user wishes to add a FIFO?)
// 5. Finally, build this so that either a FIFO or DMA could control it.
//
// Registers:
// 0. Control -- There are several types of control commands to/from
// the device, all separated and determined by how many bytes are
// to be sent to the device for the said command. Commands written
// to the control port of the device are initiated by writes
// to this register.
//
// - Writes of all { 24'h00, data[7:0] } send the single byte
// data[7:0] to the device.
// - Writes of { 16'h01, data[15:0] } send two bytes,
// data[15:0], to the device.
// - Writes of { 4'h2, 4'hx, data[23:0] } send three bytes,
// data[23:0], to the device.
// - Writes of { 4'h3, 4'hx, data[23:0] } send four bytes,
// data[23:0], then r_a[31:24] to the device.
// - Writes of { 4'h3, 4'hx, data[23:0] } send five bytes,
// data[23:0], then r_a[31:16] to the device.
// - Writes of { 4'h3, 4'hx, data[23:0] } send six bytes,
// data[23:0], then r_a[31:8] to the device.
// - Writes of { 4'h3, 4'hx, data[23:0] } send seven bytes,
// data[23:0], then r_a[31:0] to the device.
// - Writes of { 4'h3, 4'hx, data[23:0] } send eight bytes,
// data[23:0], r_a[31:16], then r_b[31:24] to the device.
// - Writes of { 4'h3, 4'hx, data[23:0] } send nine bytes,
// data[23:0], r_a[31:16], then r_b[31:16] to the device.
// - Writes of { 4'h3, 4'hx, data[23:0] } send ten bytes,
// data[23:0], r_a[31:16], then r_b[31:8] to the device.
// - Writes of { 4'h3, 4'hx, data[23:0] } send eleven bytes,
// data[23:0], r_a[31:16], then r_b[31:0] to the device.
//
// 1. A This register is used, just like the B register below, for
// setting up commands that send multiple bytes to the device.
// Be aware that the high order bits/bytes will be sent first.
// This is one of the few registers that may be read with meaning.
// Once the word is written, however, the register is cleared.
//
// 2. B This is the same as the A register, save on writes the A
// register will be written first before any bits from the B
// register. As with the A register, this value is cleared upon
// any write--regardless of whether its value is used in the
// write.
//
// 3. Data --- This is both the data and the power control register.
//
// To write data to the graphics data RAM within the device,
// simply write a 16'bit word: { 16'h00, data[15:0] } to this
// port.
//
// To change the three power bits, {reset, vccen, pmoden},
// you must also set a 1'b1 in the corresponding bit position from
// bit 16-18. Hence a:
//
// 32'h010001 sets the pmod enable bit, whereas 32'h010000 clears
// it.
// 32'h020002 sets the vcc bit, whereas 32'h010000 clears it.
//
// Multiple of the power bits can be changed at once. Each
// respective bit is only changed if it's change enable bit is
// also high.
//
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
39,7 → 144,8
o_ack, o_stall, o_data,
o_sck, o_cs_n, o_mosi, o_dbit,
o_pwr, o_int);
parameter CBITS=4; // 2^4*2@6.25ns -> 200ns/clock > 150ns min
parameter CBITS=8, // 2^4*2@6.25ns -> 200ns/clock > 150ns min
EXTRA_BUS_CLOCK = 0;
input i_clk, i_cyc, i_stb, i_we;
input [1:0] i_addr;
input [31:0] i_data;
58,42 → 164,60
lwlvl(i_clk, dev_wr, dev_dbit, dev_word, dev_len, dev_busy,
o_sck, o_cs_n, o_mosi, o_dbit);
 
`define EXTRA_WB_DELAY
`ifdef EXTRA_WB_DELAY
reg r_wb_stb, r_wb_we;
reg [31:0] r_wb_data;
reg [1:0] r_wb_addr;
always @(posedge i_clk)
r_wb_stb <= i_stb;
always @(posedge i_clk)
r_wb_we <= i_we;
always @(posedge i_clk)
r_wb_data <= i_data;
always @(posedge i_clk)
r_wb_addr <= i_addr;
`else
wire r_wb_stb, r_wb_we;
wire r_wb_data;
wire [1:0] r_wb_addr;
wire wb_stb, wb_we;
wire [31:0] wb_data;
wire [1:0] wb_addr;
 
assign r_wb_stb = i_stb;
assign r_wb_we = i_we;
assign r_wb_data = i_data;
assign r_wb_addr = i_addr;
`endif
// I've thought about bumping this from a clock at <= 100MHz up to a
// clock near 200MHz. Doing so requires an extra clock to come off
// the bus--the bus fanout is just too wide otherwise. However,
// if you don't need to ... why take the extra clock cycle? Hence
// this little snippet of code allows the rest of the controller
// to work at 200MHz or 100MHz as need be.
generate
if (EXTRA_BUS_CLOCK != 0)
begin
reg r_wb_stb, r_wb_we;
reg [31:0] r_wb_data;
reg [1:0] r_wb_addr;
always @(posedge i_clk)
r_wb_stb <= i_stb;
always @(posedge i_clk)
r_wb_we <= i_we;
always @(posedge i_clk)
r_wb_data <= i_data;
always @(posedge i_clk)
r_wb_addr <= i_addr;
 
assign wb_stb = r_wb_stb;
assign wb_we = r_wb_we;
assign wb_data = r_wb_data;
assign wb_addr = r_wb_addr;
end else begin
assign wb_stb = i_stb;
assign wb_we = i_we;
assign wb_data = i_data;
assign wb_addr = i_addr;
end endgenerate
 
 
 
reg r_busy;
reg [3:0] r_len;
 
 
//
// Handle registers A & B. These are set either upon a write, or
// cleared (set to zero) upon any command to the control register.
//
reg [31:0] r_a, r_b;
always @(posedge i_clk)
if ((r_wb_stb)&&(r_wb_we))
if ((wb_stb)&&(wb_we))
begin
if (r_wb_addr[1:0]==2'b01)
r_a <= r_wb_data;
if (r_wb_addr[1:0]==2'b10)
r_b <= r_wb_data;
if (wb_addr[1:0]==2'b01)
r_a <= wb_data;
if (wb_addr[1:0]==2'b10)
r_b <= wb_data;
end else if (r_cstb)
begin
r_a <= 32'h00;
100,45 → 224,78
r_b <= 32'h00;
end
 
//
// Handle reads from our device. These really aren't all that
// interesting, but ... we can do them anyway. We attempt to provide
// some sort of useful value here. For example, upon reading r_a or
// r_b, you can read the current value(s) of those register(s).
always @(posedge i_clk)
begin
case (r_wb_addr)
2'b00: o_data <= { 13'h00, o_pwr, 8'h00, r_len, 3'h0, r_busy };
case (wb_addr)
2'b00: o_data <= { 13'h00, o_pwr, 8'h00, r_len, 1'b0, o_dbit, !o_cs_n, r_busy };
2'b01: o_data <= r_a;
2'b10: o_data <= r_b;
2'b11: o_data <= { 13'h00, o_pwr, 8'h00, r_len, 3'h0, r_busy };
2'b11: o_data <= { 16'h00, 13'h0, o_pwr };
endcase
end
 
initial o_ack = 1'b0;
always @(posedge i_clk)
o_ack <= r_wb_stb;
o_ack <= wb_stb;
assign o_stall = 1'b0;
 
reg r_cstb, r_dstb, r_pstb;
reg [23:0] r_data;
reg r_cstb, r_dstb, r_pstb, r_pre_busy;
reg [18:0] r_data;
initial r_cstb = 1'b0;
initial r_dstb = 1'b0;
initial r_pstb = 1'b0;
initial r_pre_busy = 1'b0; // Used to clear the interrupt a touch earlier
 
// The control strobe. This will be true if we need to command a
// control interaction.
always @(posedge i_clk)
r_cstb <= (r_wb_stb)&&(r_wb_addr[1:0]==2'b00);
r_cstb <= (wb_stb)&&(wb_we)&&(wb_addr[1:0]==2'b00);
 
// The data strobe, true if we need to command a data interaction.
always @(posedge i_clk)
r_dstb <= (r_wb_stb)&&(r_wb_addr[1:0]==2'b11)&&(r_wb_data[22:20]==3'h0);
r_dstb <= (wb_stb)&&(wb_we)&&(wb_addr[1:0]==2'b11)&&(wb_data[18:16]==3'h0);
 
// The power strobe. True if we are about to adjust the power and/or
// reset bits.
always @(posedge i_clk) // Power strobe, change power settings
r_pstb <= (wb_stb)&&(wb_we)&&(wb_addr[1:0]==2'b11)&&(wb_data[18:16]!=3'h0);
 
// Pre-busy: true if either r_cstb or r_dstb is true, and true on the
// same clock they are true. This is to support our interrupt, by
// clearing the interrupt one clock earlier--lest the DMA decide to send
// two words our way instead of one.
always @(posedge i_clk)
r_pstb <= (r_wb_stb)&&(r_wb_addr[1:0]==2'b11)&&(r_wb_data[22:20]!=3'h0);
r_pre_busy <= (wb_stb)&&(wb_we)&&
((wb_addr[1:0]==2'b11)||(wb_addr[1:0]==2'b00));
 
// But ... to use these strobe values, we are now one more clock
// removed from the bus. We need something that matches this, so let's
// delay our bus data one more clock 'til the time when we actually use
// it.
always @(posedge i_clk)
r_data <= r_wb_data[23:0];
r_data <= wb_data[18:0];
 
initial o_pwr = 3'h0;
always @(posedge i_clk)
if (r_pstb)
o_pwr <= ((o_pwr)&(~r_data[22:20]))
|((r_wb_data[18:16])&(r_data[22:20]));
o_pwr <= ((o_pwr)&(~r_data[18:16]))
|((r_data[2:0])&(r_data[18:16]));
 
// Sadly, because our commands can have a whole slew of different
// lengths, and because these lengths can be ... difficult to
// decipher from the command (especially the first two lengths),
// this quick case statement is needed to decode the amount of bytes
// that will be sent.
reg [3:0] b_len;
always @(posedge i_clk)
casez(r_wb_data[31:28])
4'b000?: b_len <= (r_wb_data[16])? 4'h1:4'h2;
casez(wb_data[31:28])
4'b0000: b_len <= (wb_data[16])? 4'h2:4'h1;
4'b0001: b_len <= 4'h2;
4'b0010: b_len <= 4'h3;
4'b0011: b_len <= 4'h4;
4'b0100: b_len <= 4'h5;
151,38 → 308,84
default: b_len <= 4'h0;
endcase
 
reg [87:0] r_sreg;
//
// On the next clock, we're going to set our data register to
// whatever's in register A, and B, and ... something of the data
// written to the control register. Because this must all be
// written on the most-significant bits of a word, we pause a moment
// here to move the control word that was writen to our bus up
// by an amount given by the length of our message. That way, you
// can write to the bottom bits of the register, and yet still end
// up in the top several bits of the following register.
//
reg [23:0] c_data;
always @(posedge i_clk)
if (wb_data[31:29] != 3'h0)
c_data <= wb_data[23:0];
else if (wb_data[16])
c_data <= { wb_data[15:0], 8'h00 };
else
c_data <= { wb_data[7:0], 16'h00 };
 
//
// Finally, after massaging the incoming data off our bus, we finally
// get to controlling the lower level controller and sending the
// data to the device itself.
//
// The basic idea is this: we use r_busy to know if we are in the
// middle of an operation, or whether or not we will be responsive to
// the bus. r_sreg holds the data we wish to send, and r_len the
// number of bytes within r_sreg that remain to be sent. The controller
// will accept up to 32-bits at a time, so once we issue a command
// (dev_wr & !dev_busy), we transition to either the next command.
// Once all the data has been sent, and the device is now idle, we
// clear r_busy and therefore become responsive to the bus again.
//
//
reg [87:0] r_sreg; // Composed of 24-bits, 32-bits, and 32-bits
initial r_busy = 1'b0;
initial dev_wr = 1'b1;
always @(posedge i_clk)
if ((~r_busy)&&(r_cstb))
begin
dev_wr <= 1'b0;
dev_dbit <= 1'b0;
r_sreg <= { r_data[23:0], r_a, r_b };
r_len <= b_len;
r_busy <= (b_len != 4'h0);
if (b_len == 4'h1)
r_sreg[87:72] <= { r_data[7:0], r_data[7:0] };
else if (b_len == 4'h2)
r_sreg[87:72] <= r_data[15:0];
else
r_sreg[87:72] <= r_data[23:8];
end else if ((~dev_busy)&&(r_dstb))
begin
dev_wr <= 1'b0;
dev_dbit <= 1'b1;
r_sreg <= { r_data[15:0], 72'h00 };
r_len <= 4'h2;
r_busy <= 1'b1;
end else if ((r_busy)&&(~dev_busy))
begin
dev_word <= r_sreg[87:56];
r_sreg <= { r_sreg[55:0], 32'h00 };
dev_len <= (r_len > 4'h4)? 2'b11:(r_len[1:0]+2'b11);
r_len <= (r_len > 4'h4) ? (r_len-4'h4):0;
end else if (r_busy)
r_busy <= (r_len != 4'h0);
dev_wr <= 1'b0;
if ((~r_busy)&&(r_cstb))
begin
dev_dbit <= 1'b0;
r_sreg <= { c_data[23:0], r_a, r_b };
r_len <= b_len;
r_busy <= (b_len != 4'h0);
end else if ((~r_busy)&&(r_dstb))
begin
dev_dbit <= 1'b1;
r_sreg <= { r_data[15:0], 72'h00 };
r_len <= 4'h2;
r_busy <= 1'b1;
end else if ((r_busy)&&(!dev_busy))
begin
// Issue the command to write up to 32-bits at a time
dev_wr <= (r_len != 4'h0);
dev_word <= r_sreg[87:56];
r_sreg <= { r_sreg[55:0], 32'h00 };
dev_len <= (r_len > 4'h4)? 2'b11:(r_len[1:0]+2'b11);
if (dev_wr)
r_len <= (r_len > 4'h4) ? (r_len-4'h4):0;
r_busy <= (dev_wr)||(r_len != 4'h0)&&(!dev_wr);
end else if (r_busy) // & dev_busy
begin
dev_wr <= (r_len != 4'h0);
dev_len <= (r_len > 4'h4)? 2'b11:(r_len[1:0]+2'b11);
end
end
 
assign o_int = (~r_busy);
//
// Here, we pick a self-clearing interrupt input. This will set the
// interrupt any time we are idle, and will automatically clear itself
// any time we become busy. This should be sufficient to allow the
// DMA controller to send things to the card.
//
// Of course ... if you are not running in any sort of interrupt mode,
// you *could* just ignore this line and poll the busy bit instead.
//
assign o_int = (~r_busy)&&(!r_pre_busy);
 
endmodule

powered by: WebSVN 2.1.0

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