From 59722f482aec0a3997c7ef5db677a082dac32c04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20W=C5=82ostowski?= <tomasz.wlostowski@cern.ch> Date: Wed, 9 Jan 2013 14:26:53 +0100 Subject: [PATCH] wishbone: added wb_simple_pwm PWM controller Conflicts: modules/wishbone/Manifest.py --- modules/wishbone/Manifest.py | 1 + modules/wishbone/wb_simple_pwm/Manifest.py | 5 + .../wishbone/wb_simple_pwm/simple_pwm_wb.vhd | 372 ++++++++++++++++++ .../wishbone/wb_simple_pwm/simple_pwm_wb.wb | 121 ++++++ .../wb_simple_pwm/simple_pwm_wbgen2_pkg.vhd | 129 ++++++ .../wishbone/wb_simple_pwm/wb_simple_pwm.vhd | 214 ++++++++++ .../wishbone/wb_simple_pwm/xwb_simple_pwm.vhd | 108 +++++ 7 files changed, 950 insertions(+) create mode 100644 modules/wishbone/wb_simple_pwm/Manifest.py create mode 100644 modules/wishbone/wb_simple_pwm/simple_pwm_wb.vhd create mode 100644 modules/wishbone/wb_simple_pwm/simple_pwm_wb.wb create mode 100644 modules/wishbone/wb_simple_pwm/simple_pwm_wbgen2_pkg.vhd create mode 100644 modules/wishbone/wb_simple_pwm/wb_simple_pwm.vhd create mode 100644 modules/wishbone/wb_simple_pwm/xwb_simple_pwm.vhd diff --git a/modules/wishbone/Manifest.py b/modules/wishbone/Manifest.py index 5f2bf672..4cbb021d 100644 --- a/modules/wishbone/Manifest.py +++ b/modules/wishbone/Manifest.py @@ -17,6 +17,7 @@ def __helper(): "wb_clock_crossing", "wb_dma", "wb_serial_lcd", + "wb_simple_pwm", "wbgen2" ] if (target == "altera"): dirs.extend(["wb_pcie"]); diff --git a/modules/wishbone/wb_simple_pwm/Manifest.py b/modules/wishbone/wb_simple_pwm/Manifest.py new file mode 100644 index 00000000..e5018a82 --- /dev/null +++ b/modules/wishbone/wb_simple_pwm/Manifest.py @@ -0,0 +1,5 @@ +files = ["simple_pwm_wbgen2_pkg.vhd", +"simple_pwm_wb.vhd", +"wb_simple_pwm.vhd", +"xwb_simple_pwm.vhd" +]; diff --git a/modules/wishbone/wb_simple_pwm/simple_pwm_wb.vhd b/modules/wishbone/wb_simple_pwm/simple_pwm_wb.vhd new file mode 100644 index 00000000..1db87840 --- /dev/null +++ b/modules/wishbone/wb_simple_pwm/simple_pwm_wb.vhd @@ -0,0 +1,372 @@ +--------------------------------------------------------------------------------------- +-- Title : Wishbone slave core for Simple Pulse Width Modulation Controller +--------------------------------------------------------------------------------------- +-- File : simple_pwm_wb.vhd +-- Author : auto-generated by wbgen2 from simple_pwm_wb.wb +-- Created : Thu Dec 20 11:32:19 2012 +-- Standard : VHDL'87 +--------------------------------------------------------------------------------------- +-- THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE simple_pwm_wb.wb +-- DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY! +--------------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +use work.spwm_wbgen2_pkg.all; + + +entity simple_pwm_wb is + port ( + rst_n_i : in std_logic; + clk_sys_i : in std_logic; + wb_adr_i : in std_logic_vector(3 downto 0); + wb_dat_i : in std_logic_vector(31 downto 0); + wb_dat_o : out std_logic_vector(31 downto 0); + wb_cyc_i : in std_logic; + wb_sel_i : in std_logic_vector(3 downto 0); + wb_stb_i : in std_logic; + wb_we_i : in std_logic; + wb_ack_o : out std_logic; + wb_stall_o : out std_logic; + regs_i : in t_spwm_in_registers; + regs_o : out t_spwm_out_registers + ); +end simple_pwm_wb; + +architecture syn of simple_pwm_wb is + +signal spwm_cr_presc_int : std_logic_vector(15 downto 0); +signal spwm_cr_period_int : std_logic_vector(15 downto 0); +signal ack_sreg : std_logic_vector(9 downto 0); +signal rddata_reg : std_logic_vector(31 downto 0); +signal wrdata_reg : std_logic_vector(31 downto 0); +signal bwsel_reg : std_logic_vector(3 downto 0); +signal rwaddr_reg : std_logic_vector(3 downto 0); +signal ack_in_progress : std_logic ; +signal wr_int : std_logic ; +signal rd_int : std_logic ; +signal allones : std_logic_vector(31 downto 0); +signal allzeros : std_logic_vector(31 downto 0); + +begin +-- Some internal signals assignments. For (foreseen) compatibility with other bus standards. + wrdata_reg <= wb_dat_i; + bwsel_reg <= wb_sel_i; + rd_int <= wb_cyc_i and (wb_stb_i and (not wb_we_i)); + wr_int <= wb_cyc_i and (wb_stb_i and wb_we_i); + allones <= (others => '1'); + allzeros <= (others => '0'); +-- +-- Main register bank access process. + process (clk_sys_i, rst_n_i) + begin + if (rst_n_i = '0') then + ack_sreg <= "0000000000"; + ack_in_progress <= '0'; + rddata_reg <= "00000000000000000000000000000000"; + spwm_cr_presc_int <= "0000000000000000"; + spwm_cr_period_int <= "0000000000000000"; + regs_o.dr0_load_o <= '0'; + regs_o.dr1_load_o <= '0'; + regs_o.dr2_load_o <= '0'; + regs_o.dr3_load_o <= '0'; + regs_o.dr4_load_o <= '0'; + regs_o.dr5_load_o <= '0'; + regs_o.dr6_load_o <= '0'; + regs_o.dr7_load_o <= '0'; + elsif rising_edge(clk_sys_i) then +-- advance the ACK generator shift register + ack_sreg(8 downto 0) <= ack_sreg(9 downto 1); + ack_sreg(9) <= '0'; + if (ack_in_progress = '1') then + if (ack_sreg(0) = '1') then + regs_o.dr0_load_o <= '0'; + regs_o.dr1_load_o <= '0'; + regs_o.dr2_load_o <= '0'; + regs_o.dr3_load_o <= '0'; + regs_o.dr4_load_o <= '0'; + regs_o.dr5_load_o <= '0'; + regs_o.dr6_load_o <= '0'; + regs_o.dr7_load_o <= '0'; + ack_in_progress <= '0'; + else + regs_o.dr0_load_o <= '0'; + regs_o.dr1_load_o <= '0'; + regs_o.dr2_load_o <= '0'; + regs_o.dr3_load_o <= '0'; + regs_o.dr4_load_o <= '0'; + regs_o.dr5_load_o <= '0'; + regs_o.dr6_load_o <= '0'; + regs_o.dr7_load_o <= '0'; + end if; + else + if ((wb_cyc_i = '1') and (wb_stb_i = '1')) then + case rwaddr_reg(3 downto 0) is + when "0000" => + if (wb_we_i = '1') then + spwm_cr_presc_int <= wrdata_reg(15 downto 0); + spwm_cr_period_int <= wrdata_reg(31 downto 16); + end if; + rddata_reg(15 downto 0) <= spwm_cr_presc_int; + rddata_reg(31 downto 16) <= spwm_cr_period_int; + ack_sreg(0) <= '1'; + ack_in_progress <= '1'; + when "0001" => + if (wb_we_i = '1') then + end if; + rddata_reg(3 downto 0) <= regs_i.sr_n_channels_i; + rddata_reg(4) <= 'X'; + rddata_reg(5) <= 'X'; + rddata_reg(6) <= 'X'; + rddata_reg(7) <= 'X'; + rddata_reg(8) <= 'X'; + rddata_reg(9) <= 'X'; + rddata_reg(10) <= 'X'; + rddata_reg(11) <= 'X'; + rddata_reg(12) <= 'X'; + rddata_reg(13) <= 'X'; + rddata_reg(14) <= 'X'; + rddata_reg(15) <= 'X'; + rddata_reg(16) <= 'X'; + rddata_reg(17) <= 'X'; + rddata_reg(18) <= 'X'; + rddata_reg(19) <= 'X'; + rddata_reg(20) <= 'X'; + rddata_reg(21) <= 'X'; + rddata_reg(22) <= 'X'; + rddata_reg(23) <= 'X'; + rddata_reg(24) <= 'X'; + rddata_reg(25) <= 'X'; + rddata_reg(26) <= 'X'; + rddata_reg(27) <= 'X'; + rddata_reg(28) <= 'X'; + rddata_reg(29) <= 'X'; + rddata_reg(30) <= 'X'; + rddata_reg(31) <= 'X'; + ack_sreg(0) <= '1'; + ack_in_progress <= '1'; + when "0010" => + if (wb_we_i = '1') then + regs_o.dr0_load_o <= '1'; + end if; + rddata_reg(15 downto 0) <= regs_i.dr0_i; + rddata_reg(16) <= 'X'; + rddata_reg(17) <= 'X'; + rddata_reg(18) <= 'X'; + rddata_reg(19) <= 'X'; + rddata_reg(20) <= 'X'; + rddata_reg(21) <= 'X'; + rddata_reg(22) <= 'X'; + rddata_reg(23) <= 'X'; + rddata_reg(24) <= 'X'; + rddata_reg(25) <= 'X'; + rddata_reg(26) <= 'X'; + rddata_reg(27) <= 'X'; + rddata_reg(28) <= 'X'; + rddata_reg(29) <= 'X'; + rddata_reg(30) <= 'X'; + rddata_reg(31) <= 'X'; + ack_sreg(0) <= '1'; + ack_in_progress <= '1'; + when "0011" => + if (wb_we_i = '1') then + regs_o.dr1_load_o <= '1'; + end if; + rddata_reg(15 downto 0) <= regs_i.dr1_i; + rddata_reg(16) <= 'X'; + rddata_reg(17) <= 'X'; + rddata_reg(18) <= 'X'; + rddata_reg(19) <= 'X'; + rddata_reg(20) <= 'X'; + rddata_reg(21) <= 'X'; + rddata_reg(22) <= 'X'; + rddata_reg(23) <= 'X'; + rddata_reg(24) <= 'X'; + rddata_reg(25) <= 'X'; + rddata_reg(26) <= 'X'; + rddata_reg(27) <= 'X'; + rddata_reg(28) <= 'X'; + rddata_reg(29) <= 'X'; + rddata_reg(30) <= 'X'; + rddata_reg(31) <= 'X'; + ack_sreg(0) <= '1'; + ack_in_progress <= '1'; + when "0100" => + if (wb_we_i = '1') then + regs_o.dr2_load_o <= '1'; + end if; + rddata_reg(15 downto 0) <= regs_i.dr2_i; + rddata_reg(16) <= 'X'; + rddata_reg(17) <= 'X'; + rddata_reg(18) <= 'X'; + rddata_reg(19) <= 'X'; + rddata_reg(20) <= 'X'; + rddata_reg(21) <= 'X'; + rddata_reg(22) <= 'X'; + rddata_reg(23) <= 'X'; + rddata_reg(24) <= 'X'; + rddata_reg(25) <= 'X'; + rddata_reg(26) <= 'X'; + rddata_reg(27) <= 'X'; + rddata_reg(28) <= 'X'; + rddata_reg(29) <= 'X'; + rddata_reg(30) <= 'X'; + rddata_reg(31) <= 'X'; + ack_sreg(0) <= '1'; + ack_in_progress <= '1'; + when "0101" => + if (wb_we_i = '1') then + regs_o.dr3_load_o <= '1'; + end if; + rddata_reg(15 downto 0) <= regs_i.dr3_i; + rddata_reg(16) <= 'X'; + rddata_reg(17) <= 'X'; + rddata_reg(18) <= 'X'; + rddata_reg(19) <= 'X'; + rddata_reg(20) <= 'X'; + rddata_reg(21) <= 'X'; + rddata_reg(22) <= 'X'; + rddata_reg(23) <= 'X'; + rddata_reg(24) <= 'X'; + rddata_reg(25) <= 'X'; + rddata_reg(26) <= 'X'; + rddata_reg(27) <= 'X'; + rddata_reg(28) <= 'X'; + rddata_reg(29) <= 'X'; + rddata_reg(30) <= 'X'; + rddata_reg(31) <= 'X'; + ack_sreg(0) <= '1'; + ack_in_progress <= '1'; + when "0110" => + if (wb_we_i = '1') then + regs_o.dr4_load_o <= '1'; + end if; + rddata_reg(15 downto 0) <= regs_i.dr4_i; + rddata_reg(16) <= 'X'; + rddata_reg(17) <= 'X'; + rddata_reg(18) <= 'X'; + rddata_reg(19) <= 'X'; + rddata_reg(20) <= 'X'; + rddata_reg(21) <= 'X'; + rddata_reg(22) <= 'X'; + rddata_reg(23) <= 'X'; + rddata_reg(24) <= 'X'; + rddata_reg(25) <= 'X'; + rddata_reg(26) <= 'X'; + rddata_reg(27) <= 'X'; + rddata_reg(28) <= 'X'; + rddata_reg(29) <= 'X'; + rddata_reg(30) <= 'X'; + rddata_reg(31) <= 'X'; + ack_sreg(0) <= '1'; + ack_in_progress <= '1'; + when "0111" => + if (wb_we_i = '1') then + regs_o.dr5_load_o <= '1'; + end if; + rddata_reg(15 downto 0) <= regs_i.dr5_i; + rddata_reg(16) <= 'X'; + rddata_reg(17) <= 'X'; + rddata_reg(18) <= 'X'; + rddata_reg(19) <= 'X'; + rddata_reg(20) <= 'X'; + rddata_reg(21) <= 'X'; + rddata_reg(22) <= 'X'; + rddata_reg(23) <= 'X'; + rddata_reg(24) <= 'X'; + rddata_reg(25) <= 'X'; + rddata_reg(26) <= 'X'; + rddata_reg(27) <= 'X'; + rddata_reg(28) <= 'X'; + rddata_reg(29) <= 'X'; + rddata_reg(30) <= 'X'; + rddata_reg(31) <= 'X'; + ack_sreg(0) <= '1'; + ack_in_progress <= '1'; + when "1000" => + if (wb_we_i = '1') then + regs_o.dr6_load_o <= '1'; + end if; + rddata_reg(15 downto 0) <= regs_i.dr6_i; + rddata_reg(16) <= 'X'; + rddata_reg(17) <= 'X'; + rddata_reg(18) <= 'X'; + rddata_reg(19) <= 'X'; + rddata_reg(20) <= 'X'; + rddata_reg(21) <= 'X'; + rddata_reg(22) <= 'X'; + rddata_reg(23) <= 'X'; + rddata_reg(24) <= 'X'; + rddata_reg(25) <= 'X'; + rddata_reg(26) <= 'X'; + rddata_reg(27) <= 'X'; + rddata_reg(28) <= 'X'; + rddata_reg(29) <= 'X'; + rddata_reg(30) <= 'X'; + rddata_reg(31) <= 'X'; + ack_sreg(0) <= '1'; + ack_in_progress <= '1'; + when "1001" => + if (wb_we_i = '1') then + regs_o.dr7_load_o <= '1'; + end if; + rddata_reg(15 downto 0) <= regs_i.dr7_i; + rddata_reg(16) <= 'X'; + rddata_reg(17) <= 'X'; + rddata_reg(18) <= 'X'; + rddata_reg(19) <= 'X'; + rddata_reg(20) <= 'X'; + rddata_reg(21) <= 'X'; + rddata_reg(22) <= 'X'; + rddata_reg(23) <= 'X'; + rddata_reg(24) <= 'X'; + rddata_reg(25) <= 'X'; + rddata_reg(26) <= 'X'; + rddata_reg(27) <= 'X'; + rddata_reg(28) <= 'X'; + rddata_reg(29) <= 'X'; + rddata_reg(30) <= 'X'; + rddata_reg(31) <= 'X'; + ack_sreg(0) <= '1'; + ack_in_progress <= '1'; + when others => +-- prevent the slave from hanging the bus on invalid address + ack_in_progress <= '1'; + ack_sreg(0) <= '1'; + end case; + end if; + end if; + end if; + end process; + + +-- Drive the data output bus + wb_dat_o <= rddata_reg; +-- Prescaler Ratio + regs_o.cr_presc_o <= spwm_cr_presc_int; +-- Period + regs_o.cr_period_o <= spwm_cr_period_int; +-- Channel count +-- Value + regs_o.dr0_o <= wrdata_reg(15 downto 0); +-- Value + regs_o.dr1_o <= wrdata_reg(15 downto 0); +-- Value + regs_o.dr2_o <= wrdata_reg(15 downto 0); +-- Value + regs_o.dr3_o <= wrdata_reg(15 downto 0); +-- Value + regs_o.dr4_o <= wrdata_reg(15 downto 0); +-- Value + regs_o.dr5_o <= wrdata_reg(15 downto 0); +-- Value + regs_o.dr6_o <= wrdata_reg(15 downto 0); +-- Value + regs_o.dr7_o <= wrdata_reg(15 downto 0); + rwaddr_reg <= wb_adr_i; + wb_stall_o <= (not ack_sreg(0)) and (wb_stb_i and wb_cyc_i); +-- ACK signal generation. Just pass the LSB of ACK counter. + wb_ack_o <= ack_sreg(0); +end syn; diff --git a/modules/wishbone/wb_simple_pwm/simple_pwm_wb.wb b/modules/wishbone/wb_simple_pwm/simple_pwm_wb.wb new file mode 100644 index 00000000..d73b5c90 --- /dev/null +++ b/modules/wishbone/wb_simple_pwm/simple_pwm_wb.wb @@ -0,0 +1,121 @@ +-- -*- Mode: LUA; tab-width: 2 -*- + +------------------------------------------------------------------------------- +-- Title : Simple PWM controller +-- Project : General Cores Collection +------------------------------------------------------------------------------- +-- File : simple_pwm_wb.wb +-- Author : Tomasz WÅ‚ostowski +-- Company : CERN BE-CO-HT +-- Created : 2012-12-10 +-- Last update: 2013-01-09 +------------------------------------------------------------------------------- +-- Description: A simple, multichannel PWM controller (register layout) +------------------------------------------------------------------------------- +-- +-- Copyright (c) 2013 CERN / BE-CO-HT +-- +-- This source file is free software; you can redistribute it +-- and/or modify it under the terms of the GNU Lesser General +-- Public License as published by the Free Software Foundation; +-- either version 2.1 of the License, or (at your option) any +-- later version. +-- +-- This source is distributed in the hope that it will be +-- useful, but WITHOUT ANY WARRANTY; without even the implied +-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +-- PURPOSE. See the GNU Lesser General Public License for more +-- details. +-- +-- You should have received a copy of the GNU Lesser General +-- Public License along with this source; if not, download it +-- from http://www.gnu.org/licenses/lgpl-2.1l.html +-- +------------------------------------------------------------------------------- +peripheral { + name = "Simple Pulse Width Modulation Controller"; + description = "A very simple multichannel PWM controller."; + prefix = "spwm"; + hdl_entity = "simple_pwm_wb"; + + reg { + name = "Control Register"; + prefix = "CR"; + + field { + name = "Prescaler Ratio"; + description = "PWM Base clock prescaler. Divides the system clock to obtain the PWM counter clock. The division ratio is (PRESC + 1)."; + type = SLV; + size = 16; + prefix = "PRESC"; + access_bus = READ_WRITE; + access_dev = READ_ONLY; + }; + + field { + name = "Period"; + description = "PWM Cycle Period. The real-time period value <code>PERIOD * (PRESC + 1) * t_clk_sys.</code>. Acceptable values: 0..65534."; + type = SLV; + size = 16; + prefix = "PERIOD"; + access_bus = READ_WRITE; + access_dev = READ_ONLY; + }; + }; + + + reg { + name = "Status Register"; + prefix = "SR"; + field { + name = "Channel count"; + description = "Number of channels supported by this particular implementation, from 1 to 8. "; + type = SLV; + size = 4; + prefix = "N_CHANNELS"; + access_bus = READ_ONLY; + access_dev = WRITE_ONLY; + + }; + }; +}; + +drive_reg_template = + { + + reg { + name = "Channel %d Drive Register"; + + description = "Current PWM duty cycle for channel %d."; + prefix = "DR%d"; + + field { + name = "Value"; + type = SLV; + size = 16; + access_bus = READ_WRITE; + access_dev = READ_WRITE; + load = LOAD_EXT; + }; + }; +}; + +function generate_dregs(n) + local i; + + for i=0,n-1 do + local T=deepcopy(drive_reg_template); + + + foreach_reg({TYPE_REG}, function(r) + r.name = string.format(r.name, i); + r.prefix = string.format(r.prefix, i); + print(r.name) + end, T); + + + table_join(periph, T); + end +end + +generate_dregs(8); diff --git a/modules/wishbone/wb_simple_pwm/simple_pwm_wbgen2_pkg.vhd b/modules/wishbone/wb_simple_pwm/simple_pwm_wbgen2_pkg.vhd new file mode 100644 index 00000000..ab39ae28 --- /dev/null +++ b/modules/wishbone/wb_simple_pwm/simple_pwm_wbgen2_pkg.vhd @@ -0,0 +1,129 @@ +--------------------------------------------------------------------------------------- +-- Title : Wishbone slave core for Simple Pulse Width Modulation Controller +--------------------------------------------------------------------------------------- +-- File : simple_pwm_wbgen2_pkg.vhd +-- Author : auto-generated by wbgen2 from simple_pwm_wb.wb +-- Created : Thu Dec 20 11:32:19 2012 +-- Standard : VHDL'87 +--------------------------------------------------------------------------------------- +-- THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE simple_pwm_wb.wb +-- DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY! +--------------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +package spwm_wbgen2_pkg is + + + -- Input registers (user design -> WB slave) + + type t_spwm_in_registers is record + sr_n_channels_i : std_logic_vector(3 downto 0); + dr0_i : std_logic_vector(15 downto 0); + dr1_i : std_logic_vector(15 downto 0); + dr2_i : std_logic_vector(15 downto 0); + dr3_i : std_logic_vector(15 downto 0); + dr4_i : std_logic_vector(15 downto 0); + dr5_i : std_logic_vector(15 downto 0); + dr6_i : std_logic_vector(15 downto 0); + dr7_i : std_logic_vector(15 downto 0); + end record; + + constant c_spwm_in_registers_init_value: t_spwm_in_registers := ( + sr_n_channels_i => (others => '0'), + dr0_i => (others => '0'), + dr1_i => (others => '0'), + dr2_i => (others => '0'), + dr3_i => (others => '0'), + dr4_i => (others => '0'), + dr5_i => (others => '0'), + dr6_i => (others => '0'), + dr7_i => (others => '0') + ); + + -- Output registers (WB slave -> user design) + + type t_spwm_out_registers is record + cr_presc_o : std_logic_vector(15 downto 0); + cr_period_o : std_logic_vector(15 downto 0); + dr0_o : std_logic_vector(15 downto 0); + dr0_load_o : std_logic; + dr1_o : std_logic_vector(15 downto 0); + dr1_load_o : std_logic; + dr2_o : std_logic_vector(15 downto 0); + dr2_load_o : std_logic; + dr3_o : std_logic_vector(15 downto 0); + dr3_load_o : std_logic; + dr4_o : std_logic_vector(15 downto 0); + dr4_load_o : std_logic; + dr5_o : std_logic_vector(15 downto 0); + dr5_load_o : std_logic; + dr6_o : std_logic_vector(15 downto 0); + dr6_load_o : std_logic; + dr7_o : std_logic_vector(15 downto 0); + dr7_load_o : std_logic; + end record; + + constant c_spwm_out_registers_init_value: t_spwm_out_registers := ( + cr_presc_o => (others => '0'), + cr_period_o => (others => '0'), + dr0_o => (others => '0'), + dr0_load_o => '0', + dr1_o => (others => '0'), + dr1_load_o => '0', + dr2_o => (others => '0'), + dr2_load_o => '0', + dr3_o => (others => '0'), + dr3_load_o => '0', + dr4_o => (others => '0'), + dr4_load_o => '0', + dr5_o => (others => '0'), + dr5_load_o => '0', + dr6_o => (others => '0'), + dr6_load_o => '0', + dr7_o => (others => '0'), + dr7_load_o => '0' + ); + function "or" (left, right: t_spwm_in_registers) return t_spwm_in_registers; + function f_x_to_zero (x:std_logic) return std_logic; + function f_x_to_zero (x:std_logic_vector) return std_logic_vector; +end package; + +package body spwm_wbgen2_pkg is +function f_x_to_zero (x:std_logic) return std_logic is +begin +if(x = 'X' or x = 'U') then +return '0'; +else +return x; +end if; +end function; +function f_x_to_zero (x:std_logic_vector) return std_logic_vector is +variable tmp: std_logic_vector(x'length-1 downto 0); +begin +for i in 0 to x'length-1 loop +if(x(i) = 'X' or x(i) = 'U') then +tmp(i):= '0'; +else +tmp(i):=x(i); +end if; +end loop; +return tmp; +end function; +function "or" (left, right: t_spwm_in_registers) return t_spwm_in_registers is +variable tmp: t_spwm_in_registers; +begin +tmp.sr_n_channels_i := f_x_to_zero(left.sr_n_channels_i) or f_x_to_zero(right.sr_n_channels_i); +tmp.dr0_i := f_x_to_zero(left.dr0_i) or f_x_to_zero(right.dr0_i); +tmp.dr1_i := f_x_to_zero(left.dr1_i) or f_x_to_zero(right.dr1_i); +tmp.dr2_i := f_x_to_zero(left.dr2_i) or f_x_to_zero(right.dr2_i); +tmp.dr3_i := f_x_to_zero(left.dr3_i) or f_x_to_zero(right.dr3_i); +tmp.dr4_i := f_x_to_zero(left.dr4_i) or f_x_to_zero(right.dr4_i); +tmp.dr5_i := f_x_to_zero(left.dr5_i) or f_x_to_zero(right.dr5_i); +tmp.dr6_i := f_x_to_zero(left.dr6_i) or f_x_to_zero(right.dr6_i); +tmp.dr7_i := f_x_to_zero(left.dr7_i) or f_x_to_zero(right.dr7_i); +return tmp; +end function; +end package body; diff --git a/modules/wishbone/wb_simple_pwm/wb_simple_pwm.vhd b/modules/wishbone/wb_simple_pwm/wb_simple_pwm.vhd new file mode 100644 index 00000000..ac26be86 --- /dev/null +++ b/modules/wishbone/wb_simple_pwm/wb_simple_pwm.vhd @@ -0,0 +1,214 @@ +------------------------------------------------------------------------------- +-- Title : Simple Wishbone PWM Controller +-- Project : General Cores Collection (gencores) library +------------------------------------------------------------------------------- +-- File : wb_simple_pwm.vhd +-- Author : Tomasz Wlostowski +-- Company : CERN BE-Co-HT +-- Created : 2012-12-18 +-- Last update: 2012-12-20 +-- Platform : FPGA-generic +-- Standard : VHDL'93 +------------------------------------------------------------------------------- +-- Description: A simple PWM controller, supporting up to 8 channels. Aside from +-- duty cycle control, all channels share period and base frequency settings, +-- contrillable via Wishbone +------------------------------------------------------------------------------- +-- +-- This source file is free software; you can redistribute it +-- and/or modify it under the terms of the GNU Lesser General +-- Public License as published by the Free Software Foundation; +-- either version 2.1 of the License, or (at your option) any +-- later version. +-- +-- This source is distributed in the hope that it will be +-- useful, but WITHOUT ANY WARRANTY; without even the implied +-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +-- PURPOSE. See the GNU Lesser General Public License for more +-- details. +-- +-- You should have received a copy of the GNU Lesser General +-- Public License along with this source; if not, download it +-- from http://www.gnu.org/licenses/lgpl-2.1.html +-- +------------------------------------------------------------------------------- + +library ieee; +use ieee.STD_LOGIC_1164.all; +use ieee.NUMERIC_STD.all; + +use work.wishbone_pkg.all; +use work.spwm_wbgen2_pkg.all; + +entity wb_simple_pwm is + generic( + g_num_channels : integer range 1 to 8; + g_interface_mode : t_wishbone_interface_mode := PIPELINED; + g_address_granularity : t_wishbone_address_granularity := BYTE + ); + port ( + + clk_sys_i : in std_logic; + rst_n_i : in std_logic; + + wb_adr_i : in std_logic_vector(5 downto 0); + wb_dat_i : in std_logic_vector(31 downto 0); + wb_dat_o : out std_logic_vector(31 downto 0); + wb_cyc_i : in std_logic; + wb_sel_i : in std_logic_vector(3 downto 0); + wb_stb_i : in std_logic; + wb_we_i : in std_logic; + wb_ack_o : out std_logic; + wb_stall_o : out std_logic; + + pwm_o : out std_logic_vector(g_num_channels-1 downto 0) + ); +end wb_simple_pwm; + +architecture behavioral of wb_simple_pwm is + + type t_drive_array is array(0 to g_num_channels-1) of std_logic_vector(15 downto 0); + + procedure f_handle_dr_writes(index : integer; data : std_logic_vector; load : std_logic; + signal d : out t_drive_array) is + begin + if(index <= g_num_channels and load = '1') then + d(index-1) <= data; + end if; + end f_handle_dr_writes; + + component simple_pwm_wb + port ( + rst_n_i : in std_logic; + clk_sys_i : in std_logic; + wb_adr_i : in std_logic_vector(3 downto 0); + wb_dat_i : in std_logic_vector(31 downto 0); + wb_dat_o : out std_logic_vector(31 downto 0); + wb_cyc_i : in std_logic; + wb_sel_i : in std_logic_vector(3 downto 0); + wb_stb_i : in std_logic; + wb_we_i : in std_logic; + wb_ack_o : out std_logic; + wb_stall_o : out std_logic; + regs_i : in t_spwm_in_registers; + regs_o : out t_spwm_out_registers); + end component; + + signal drive : t_drive_array; + + signal regs_in : t_spwm_in_registers; + signal regs_out : t_spwm_out_registers; + + signal tick : std_logic; + signal cntr_pre, cntr_main : unsigned(15 downto 0); + +begin -- behavioral + + U_WB_Slave : simple_pwm_wb + port map ( + rst_n_i => rst_n_i, + clk_sys_i => clk_sys_i, + wb_adr_i => wb_adr_i(5 downto 2), + wb_dat_i => wb_dat_i, + wb_dat_o => wb_dat_o, + wb_cyc_i => wb_cyc_i, + wb_sel_i => wb_sel_i, + wb_stb_i => wb_stb_i, + wb_we_i => wb_we_i, + wb_ack_o => wb_ack_o, + wb_stall_o => wb_stall_o, + regs_i => regs_in, + regs_o => regs_out); + +------------------------------------------------------------------------------- +-- FIXME: this is ugly. Add register array support in wbgen2! +------------------------------------------------------------------------------- + p_drive_readback : process(drive) + begin + regs_in.dr0_i <= drive(0); + + if(g_num_channels >= 2) then + regs_in.dr1_i <= drive(1); + end if; + if(g_num_channels >= 3) then + regs_in.dr2_i <= drive(2); + end if; + if(g_num_channels >= 4) then + regs_in.dr3_i <= drive(3); + end if; + if(g_num_channels >= 5) then + regs_in.dr4_i <= drive(4); + end if; + if(g_num_channels >= 6) then + regs_in.dr5_i <= drive(5); + end if; + if(g_num_channels >= 7) then + regs_in.dr6_i <= drive(6); + end if; + if(g_num_channels >= 8) then + regs_in.dr7_i <= drive(7); + end if; + end process; + + p_drive_write : process(clk_sys_i) + begin + if rising_edge(clk_sys_i) then + if rst_n_i = '0' then + for i in 0 to g_num_channels-1 loop + drive(i) <= (others => '0'); + end loop; -- i + else + f_handle_dr_writes(1, regs_out.dr0_o, regs_out.dr0_load_o, drive); + f_handle_dr_writes(2, regs_out.dr1_o, regs_out.dr1_load_o, drive); + f_handle_dr_writes(3, regs_out.dr2_o, regs_out.dr2_load_o, drive); + f_handle_dr_writes(4, regs_out.dr3_o, regs_out.dr3_load_o, drive); + f_handle_dr_writes(5, regs_out.dr4_o, regs_out.dr4_load_o, drive); + f_handle_dr_writes(6, regs_out.dr5_o, regs_out.dr5_load_o, drive); + f_handle_dr_writes(7, regs_out.dr6_o, regs_out.dr6_load_o, drive); + f_handle_dr_writes(8, regs_out.dr7_o, regs_out.dr7_load_o, drive); + end if; + end if; + end process; + + p_prescaler : process(clk_sys_i) + begin + if rising_edge(clk_sys_i) then + if rst_n_i = '0' or std_logic_vector(cntr_pre) = regs_out.cr_presc_o then + cntr_pre <= (others => '0'); + tick <= '1'; + else + cntr_pre <= cntr_pre + 1; + tick <= '0'; + end if; + end if; + end process; + + p_main_counter : process(clk_sys_i) + begin + if rising_edge(clk_sys_i) then + if (tick = '1' and std_logic_vector(cntr_main) = regs_out.cr_period_o) or rst_n_i = '0' then + cntr_main <= (others => '0'); + elsif(tick = '1') then + cntr_main <= cntr_main + 1; + end if; + end if; + end process; + + p_comparators : process(clk_sys_i) + begin + if rising_edge(clk_sys_i) then + if rst_n_i = '0' then + pwm_o <= (others => '0'); + else + for i in 0 to g_num_channels-1 loop + if(cntr_main < unsigned(drive(i))) then + pwm_o(i) <= '1'; + else + pwm_o(i) <= '0'; + end if; + end loop; -- i + end if; + end if; + end process; + +end behavioral; diff --git a/modules/wishbone/wb_simple_pwm/xwb_simple_pwm.vhd b/modules/wishbone/wb_simple_pwm/xwb_simple_pwm.vhd new file mode 100644 index 00000000..3ae6ed87 --- /dev/null +++ b/modules/wishbone/wb_simple_pwm/xwb_simple_pwm.vhd @@ -0,0 +1,108 @@ +------------------------------------------------------------------------------- +-- Title : Simple Wishbone PWM Controller +-- Project : General Cores Collection (gencores) library +------------------------------------------------------------------------------- +-- File : xwb_simple_pwm.vhd +-- Author : Tomasz Wlostowski +-- Company : CERN BE-Co-HT +-- Created : 2012-12-18 +-- Last update: 2012-12-20 +-- Platform : FPGA-generic +-- Standard : VHDL'93 +------------------------------------------------------------------------------- +-- Description: A simple PWM controller, supporting up to 8 channels. Aside from +-- duty cycle control, all channels share period and base frequency settings, +-- contrillable via Wishbone +------------------------------------------------------------------------------- +-- +-- This source file is free software; you can redistribute it +-- and/or modify it under the terms of the GNU Lesser General +-- Public License as published by the Free Software Foundation; +-- either version 2.1 of the License, or (at your option) any +-- later version. +-- +-- This source is distributed in the hope that it will be +-- useful, but WITHOUT ANY WARRANTY; without even the implied +-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +-- PURPOSE. See the GNU Lesser General Public License for more +-- details. +-- +-- You should have received a copy of the GNU Lesser General +-- Public License along with this source; if not, download it +-- from http://www.gnu.org/licenses/lgpl-2.1.html +-- +------------------------------------------------------------------------------- +library ieee; +use ieee.std_logic_1164.all; + +library work; +use work.wishbone_pkg.all; + + + +entity xwb_simple_pwm is + generic ( + g_num_channels : integer range 1 to 8; + g_interface_mode : t_wishbone_interface_mode := PIPELINED; + g_address_granularity : t_wishbone_address_granularity := BYTE); + port( + clk_sys_i : in std_logic; + rst_n_i : in std_logic; + + -- Wishbone + slave_i : in t_wishbone_slave_in; + slave_o : out t_wishbone_slave_out; + + pwm_o : out std_logic_vector(g_num_channels-1 downto 0) + ); + +end xwb_simple_pwm; + +architecture wrapper of xwb_simple_pwm is + + component wb_simple_pwm + generic ( + g_num_channels : integer range 1 to 8; + g_interface_mode : t_wishbone_interface_mode; + g_address_granularity : t_wishbone_address_granularity); + port ( + clk_sys_i : in std_logic; + rst_n_i : in std_logic; + wb_adr_i : in std_logic_vector(5 downto 0); + wb_dat_i : in std_logic_vector(31 downto 0); + wb_dat_o : out std_logic_vector(31 downto 0); + wb_cyc_i : in std_logic; + wb_sel_i : in std_logic_vector(3 downto 0); + wb_stb_i : in std_logic; + wb_we_i : in std_logic; + wb_ack_o : out std_logic; + wb_stall_o : out std_logic; + pwm_o : out std_logic_vector(g_num_channels-1 downto 0)); + end component; + +begin -- rtl + + U_Wrapped_PWM : wb_simple_pwm + generic map ( + g_num_channels => g_num_channels, + g_interface_mode => g_interface_mode, + g_address_granularity => g_address_granularity) + port map ( + clk_sys_i => clk_sys_i, + rst_n_i => rst_n_i, + wb_adr_i => slave_i.adr(5 downto 0), + wb_dat_i => slave_i.dat, + wb_dat_o => slave_o.dat, + wb_cyc_i => slave_i.cyc, + wb_sel_i => slave_i.sel, + wb_stb_i => slave_i.stb, + wb_we_i => slave_i.we, + wb_ack_o => slave_o.ack, + wb_stall_o => slave_o.stall, + pwm_o => pwm_o); + + slave_o.err <= '0'; + slave_o.rty <= '0'; + slave_o.int <= '0'; + +end wrapper; -- GitLab