SDVD/design/nexys_a7_top.sv
Waylon Cude f840d27b8e
All checks were successful
ci/woodpecker/push/test-workflow Pipeline was successful
Demo commit
The audio output is still messed up, but this commit gets everything as
ready as it can get. Fixed up all the testbenches and added state
machines for everything
2025-06-10 13:26:35 -07:00

154 lines
4.0 KiB
Systemverilog

/***
* nexys_a7_top.sv - top level design module specific to Nexys A7100T.
*
* @author: Waylon Cude, Dilanthi Prentice
* @date: 6/12/2025
*
* **/
`ifdef VERILATOR
`include "sdvd_defs.sv"
`endif
import sdvd_defs::SPEED;
module nexys_a7_top(
input logic CLK100MHZ, CPU_RESETN,
input logic BTNC, BTNR,
output logic AUD_PWM, AUD_SD,
output logic CA,CB,CC,CD,CE,CF,CG,
output logic [7:0] AN,
output wire LED[0:0],
output wire SD_RESET,SD_SCK,
inout wire [3:0] SD_DAT,
inout wire SD_CMD,
input wire SD_CD
);
// Active high reset
wire reset;
assign reset = ~CPU_RESETN;
logic clk_1khz, clk_10hz;
logic clk_48khz, clk_1mhz;
logic seconds_pulse;
SPEED speed;
audio_buffer_interface audio_interface();
// Map C{A-G} to an array of 7-segment displays
wire [6:0] segments [7:0];
wire [2:0] segment_mux_select;
// These segments are currently unused
assign segments[7] = 0;
assign segments[6] = 0;
// These are the ones we're using
assign {CA,CB,CC,CD,CE,CF,CG} = ~segments[segment_mux_select];
logic [$clog2(60)-1:0] seconds;
logic [$clog2(60)-1:0] minutes;
logic [$clog2(60)-1:0] hours;
logic [15:0] audio_sample;
logic sd_ready;
logic playing;
assign LED[0] = playing;
assign AUD_SD = playing;
low_freq_clock_gen clockGen(CLK100MHZ, reset, speed, 'z, clk_10hz, seconds_pulse);
modular_clock_gen #(100_000) anodeClock(CLK100MHZ, reset, clk_1khz);
// Create a clock with a divisor of 2083, making ~48khz
modular_clock_gen #(2083) audioClock(CLK100MHZ, reset, clk_48khz);
modular_clock_gen #(100) pwmClock(CLK100MHZ, reset, clk_1mhz);
// Count the number on seconds, hours, and minutes elapsed
// If the speed is faster this will pulse more often than once a second
// but will still theoretically be a second of video time
always_ff @(posedge seconds_pulse or posedge reset) begin
if (reset) begin
seconds <= 0;
minutes <= 0;
hours <= 0;
end
else if (seconds == 59) begin
seconds <= 0;
if (minutes == 59) begin
minutes <= 0;
hours <= hours + 1;
end
else
minutes <= minutes + 1;
end
else
seconds <= seconds + 1;
end
display_anode_driver anodeDriver(clk_1khz,reset,AN,segment_mux_select);
sixty_display secondsSegment (seconds, segments[1], segments[0]);
sixty_display minutesSegment (minutes, segments[3], segments[2]);
sixty_display hoursSegment (hours, segments[5], segments[4]);
// Run the playback speed state machine at a lower rate
// Gets rid of button bouncing
playback_controller playbackController (clk_10hz,reset,BTNC, BTNR, speed);
`ifdef ROM
rom_sd #("even_flow_16.mem") romSdPlayer(clk_1mhz,reset,sd_ready,audio_interface.driver);
assign {SD_RESET,SD_DAT,SD_CMD,SD_SCK} = 'z;
audio_buffer audioBuffer(
clk_48khz,
reset,
sd_ready,
'0, // stop signal not used right now
speed,
playing,
audio_sample,
audio_interface.receiver
);
pwm audioOutput(CLK100MHZ, reset, clk_48khz, audio_sample, AUD_PWM);
`else
// Power the sd slot
assign SD_RESET = 0;
// We don't use more than one dat line
logic clk_100khz;
logic clk_25mhz;
// Actually 200khz now
modular_clock_gen #(500) slowSdClock(CLK100MHZ, reset, clk_100khz);
// Try clocking this slower than max speed
// To see if that makes it actually work ...
// If these are different speeds bad things happen :) oops
modular_clock_gen #(400) fastSdClock(CLK100MHZ, reset, clk_25mhz);
sd_controller realSdPlayer(
clk_100khz,
clk_25mhz,
CLK100MHZ,
reset,
SD_DAT,
SD_CMD,
sd_ready,
SD_SCK,
audio_interface.driver
);
audio_buffer #(.SIZE(8)) audioBuffer(
clk_48khz,
reset,
sd_ready,
'0, // stop signal not used right now
speed,
playing,
audio_sample,
audio_interface.receiver
);
pwm #(8) audioOutput(CLK100MHZ, reset, clk_48khz, audio_sample, AUD_PWM);
`endif
endmodule