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 |