153 lines
3.2 KiB
Verilog
153 lines
3.2 KiB
Verilog
/* Copyright 2024 (C) Peter McGoron
|
|
*
|
|
* This file is a part of Upsilon, a free and open source software project.
|
|
* For license terms, refer to the files in `doc/copying` in the Upsilon
|
|
* source distribution.
|
|
*/
|
|
|
|
module waveform_sim #(
|
|
parameter RAM_START_ADDR = 32'h0,
|
|
parameter SPI_START_ADDR = 32'h10000000,
|
|
parameter COUNTER_MAX_WID = 16,
|
|
parameter TIMER_WID = 16
|
|
) (
|
|
input clk,
|
|
|
|
/* Waveform output control */
|
|
input run,
|
|
output [COUNTER_MAX_WID-1:0] cntr,
|
|
input do_loop,
|
|
output finished,
|
|
output ready,
|
|
input [COUNTER_MAX_WID-1:0] wform_size,
|
|
output [TIMER_WID-1:0] timer,
|
|
input [TIMER_WID-1:0] timer_spacing,
|
|
|
|
/* data requests to Verilator */
|
|
|
|
output reg [32-1:0] offset,
|
|
output reg [32-1:0] spi_data,
|
|
input [32-1:0] ram_data,
|
|
output reg [1:0] enable,
|
|
input ram_finished,
|
|
|
|
/* Misc */
|
|
input [32-1:0] spi_max_wait
|
|
);
|
|
|
|
wire [32-1:0] wb_adr;
|
|
wire wb_cyc;
|
|
wire wb_we;
|
|
wire wb_stb;
|
|
wire [32-1:0] wb_dat_w;
|
|
reg [32-1:0] wb_dat_r;
|
|
wire [4-1:0] wb_sel;
|
|
reg wb_ack = 0;
|
|
|
|
waveform #(
|
|
.RAM_START_ADDR(RAM_START_ADDR),
|
|
.SPI_START_ADDR(SPI_START_ADDR),
|
|
.COUNTER_MAX_WID(COUNTER_MAX_WID),
|
|
.TIMER_WID(TIMER_WID)
|
|
) wf (
|
|
.clk(clk),
|
|
.run(run),
|
|
.cntr(cntr),
|
|
.do_loop(do_loop),
|
|
.finished(finished),
|
|
.ready(ready),
|
|
.wform_size(wform_size),
|
|
.timer(timer),
|
|
.timer_spacing(timer_spacing),
|
|
.wb_adr(wb_adr),
|
|
.wb_cyc(wb_cyc),
|
|
.wb_we(wb_we),
|
|
.wb_stb(wb_stb),
|
|
.wb_dat_w(wb_dat_w),
|
|
.wb_dat_r(wb_dat_r),
|
|
.wb_ack(wb_ack),
|
|
.wb_sel(wb_sel)
|
|
);
|
|
|
|
reg [32-1:0] spi_cntr = 0;
|
|
reg spi_armed = 0;
|
|
reg spi_running = 0;
|
|
reg spi_ready_to_arm = 1;
|
|
reg spi_finished = 0;
|
|
|
|
/* SPI Delay simulation */
|
|
|
|
always @ (posedge clk) if ((spi_armed || spi_running) && !spi_finished) begin
|
|
spi_running <= 1;
|
|
spi_ready_to_arm <= 0;
|
|
if (spi_cntr == spi_max_wait) begin
|
|
spi_cntr <= 0;
|
|
spi_finished <= 1;
|
|
end else begin
|
|
spi_cntr <= spi_cntr + 1;
|
|
end
|
|
end else if (spi_finished) begin
|
|
spi_running <= 0;
|
|
if (!spi_armed) begin
|
|
spi_finished <= 0;
|
|
spi_ready_to_arm <= 1;
|
|
end
|
|
end
|
|
|
|
/* Bus handlers */
|
|
|
|
always @* if (wb_we && wb_sel != 4'b1111)
|
|
$error("Write request without writing entire word");
|
|
|
|
always @ (posedge clk) if (wb_cyc & wb_stb & ~wb_ack) begin
|
|
if (wb_adr >= SPI_START_ADDR) case (wb_adr)
|
|
SPI_START_ADDR | 32'h4: if (wb_we) begin
|
|
spi_armed <= wb_dat_w[0];
|
|
wb_ack <= 1;
|
|
end else begin
|
|
wb_dat_r[0] <= spi_armed;
|
|
wb_ack <= 1;
|
|
end
|
|
SPI_START_ADDR | 32'hC: begin
|
|
if (!wb_we) $error("Waveform should never read the to_slave register");
|
|
|
|
/* Write SPI Data to verilator immediately, but have a counter
|
|
* running in the background to simulate SPI transfer */
|
|
spi_data <= wb_dat_w;
|
|
enable <= 2'b10;
|
|
if (ram_finished) begin
|
|
enable <= 0;
|
|
wb_ack <= 1;
|
|
end
|
|
end
|
|
SPI_START_ADDR | 32'h10: begin
|
|
if (wb_we) $error("Blocking SPI status check is read only register");
|
|
if (spi_ready_to_arm || spi_finished) begin
|
|
wb_dat_r[0] <= spi_ready_to_arm;
|
|
wb_dat_r[1] <= spi_finished;
|
|
wb_ack <= 1;
|
|
end
|
|
end
|
|
default: begin
|
|
$error("Invalid SPI address");
|
|
end
|
|
endcase else begin
|
|
offset <= wb_adr;
|
|
enable <= 2'b01;
|
|
if (ram_finished) begin
|
|
wb_dat_r <= ram_data;
|
|
enable <= 0;
|
|
wb_ack <= 1;
|
|
end
|
|
end
|
|
end else if (~wb_cyc) begin
|
|
wb_ack <= 0;
|
|
end
|
|
|
|
initial begin
|
|
$dumpfile("waveform.fst");
|
|
$dumpvars;
|
|
end
|
|
|
|
endmodule
|