From 4bb4f54dd9ed1501f28b29a41772ef63bc2dc768 Mon Sep 17 00:00:00 2001 From: rej Date: Tue, 19 Sep 2023 12:33:54 +0200 Subject: [PATCH] PWM output on pin 0 --- info.yaml | 3 ++- src/Makefile | 2 +- src/pwm.v | 29 +++++++++++++++++++++++++++++ src/test.py | 7 ++++--- src/tt_um_rejunity_sn76489.v | 10 +++++++++- 5 files changed, 45 insertions(+), 6 deletions(-) create mode 100644 src/pwm.v diff --git a/info.yaml b/info.yaml index 36be5b0..01d5310 100644 --- a/info.yaml +++ b/info.yaml @@ -9,6 +9,7 @@ project: - attenuation.v - tone.v - noise.v + - pwm.v - tt_um_rejunity_sn76489.v top_module: "tt_um_rejunity_sn76489" # Put the name of your top module here, must start with "tt_um_". Make it unique by including your github username @@ -47,7 +48,7 @@ documentation: - data7 # A description of what the outputs do (e.g. status LED, SPI MISO, etc) outputs: - - snd_out + - snd_out (pwm) - none - none - none diff --git a/src/Makefile b/src/Makefile index d33e39a..f3f64be 100644 --- a/src/Makefile +++ b/src/Makefile @@ -9,7 +9,7 @@ TOPLEVEL_LANG ?= verilog ifneq ($(GATES),yes) # this is the only part you should need to modify: -VERILOG_SOURCES += $(PWD)/attenuation.v $(PWD)/tone.v $(PWD)/noise.v $(PWD)/tt_um_rejunity_sn76489.v $(PWD)/tb.v +VERILOG_SOURCES += $(PWD)/attenuation.v $(PWD)/tone.v $(PWD)/noise.v $(PWD)/pwm.v $(PWD)/tt_um_rejunity_sn76489.v $(PWD)/tb.v else diff --git a/src/pwm.v b/src/pwm.v new file mode 100644 index 0000000..7654529 --- /dev/null +++ b/src/pwm.v @@ -0,0 +1,29 @@ +// A first-order sigma-delta modulator +// It resembles a PWM, but actually is a PDM (Pulse Density Modulation) +// https://en.wikipedia.org/wiki/Pulse-density_modulation +// +// Implementaion based on https://www.fpga4fun.com/PWM_DAC_2.html + +module pwm #( parameter VALUE_BITS = 8 ) ( + input wire clk, + input wire reset, + + input wire [VALUE_BITS-1:0] value, + + output wire out +); + localparam ACCUMULATOR_BITS = VALUE_BITS + 1; + reg [ACCUMULATOR_BITS-1:0] accumulator; + + always @(posedge clk) begin + if (reset) begin + accumulator <= 0; + end else begin + // greater the value, the more often accumulator overflows + // every time the accumulator overflows, PDM outputs 1 + accumulator <= accumulator[VALUE_BITS-1:0] + value; + end + end + + assign out = accumulator[ACCUMULATOR_BITS-1]; // an overflow bit of the accumulator is the output of PDM +endmodule diff --git a/src/test.py b/src/test.py index 5a72a40..fcb3bbb 100644 --- a/src/test.py +++ b/src/test.py @@ -21,7 +21,8 @@ def print_chip_state(dut): '{:4d}'.format(int(internal.noise[0].gen.tone.counter.value)), ">" if internal.noise[0].gen.tone.out == 1 else " ", internal.noise[0].gen.lfsr.value, ">>", - dut.uo_out.value) + '{:3d}'.format(int(dut.uo_out.value >> 1)), + "@" if dut.uo_out[0].value == 1 else ".") except: print(dut.uo_out.value) @@ -42,10 +43,10 @@ async def test_psg(dut): dut._log.info("init") for val in [ # attenuation - 0b1_00_1_1111, # channel 0 + 0b1_00_1_1110, # channel 0 0b1_01_1_1111, # channel 1 0b1_10_1_1111, # channel 2 - 0b1_11_1_1111, # channel 3 + 0b1_11_1_1110, # channel 3 # frequency 0b1_00_0_0001, # tone 0 0b1_01_0_0001, # tone 1 diff --git a/src/tt_um_rejunity_sn76489.v b/src/tt_um_rejunity_sn76489.v index 6d55553..186106b 100644 --- a/src/tt_um_rejunity_sn76489.v +++ b/src/tt_um_rejunity_sn76489.v @@ -151,11 +151,19 @@ module tt_um_rejunity_sn76489 #( parameter NUM_TONES = 3, parameter NUM_NOISES = end endgenerate + // sum up all the channels, clamp to the highest value when overflown localparam OVERFLOW_BITS = $clog2(NUM_CHANNELS); localparam ACCUMULATOR_BITS = CHANNEL_OUTPUT_BITS + OVERFLOW_BITS; wire [ACCUMULATOR_BITS-1:0] master; assign master = (volumes[0] + volumes[1] + volumes[2] + volumes[3]); - assign uo_out = (master[ACCUMULATOR_BITS-1 -: OVERFLOW_BITS] == 0) ? master[CHANNEL_OUTPUT_BITS-1 -: MASTER_OUTPUT_BITS] : {MASTER_OUTPUT_BITS{1'b1}}; + assign uo_out[7:1] = (master[ACCUMULATOR_BITS-1 -: OVERFLOW_BITS] == 0) ? master[CHANNEL_OUTPUT_BITS-1 -: MASTER_OUTPUT_BITS] : {MASTER_OUTPUT_BITS{1'b1}}; + + pwm #(.VALUE_BITS(MASTER_OUTPUT_BITS)) pwm ( + .clk(clk), + .reset(reset), + .value(uo_out[7:1]), + .out(uo_out[0]) + ); endmodule