diff options
Diffstat (limited to 'fpga/usrp3/top/e31x/axi_pmu.v')
-rw-r--r-- | fpga/usrp3/top/e31x/axi_pmu.v | 250 |
1 files changed, 250 insertions, 0 deletions
diff --git a/fpga/usrp3/top/e31x/axi_pmu.v b/fpga/usrp3/top/e31x/axi_pmu.v new file mode 100644 index 000000000..97607c272 --- /dev/null +++ b/fpga/usrp3/top/e31x/axi_pmu.v @@ -0,0 +1,250 @@ +// +// Copyright 2015 Ettus Research, A National Instruments Company +// SPDX-License-Identifier: LGPL-3.0 +// +// Description: AXI PMU +// + +module axi_pmu +#( + parameter DEPTH = 64 +) +( + // sys connect + input s_axi_aclk, + input s_axi_areset, + + // spi slave port + input ss, + input mosi, + input sck, + output miso, + + // axi4 lite slave port + input [31:0] s_axi_awaddr, + input s_axi_awvalid, + output s_axi_awready, + + input [31:0] s_axi_wdata, + input [3:0] s_axi_wstrb, + input s_axi_wvalid, + output s_axi_wready, + + output [1:0] s_axi_bresp, + output s_axi_bvalid, + input s_axi_bready, + + input [31:0] s_axi_araddr, + input s_axi_arvalid, + output s_axi_arready, + + output [31:0] s_axi_rdata, + output [1:0] s_axi_rresp, + output s_axi_rvalid, + input s_axi_rready, + + output s_axi_irq +); + + wire spi_stb; + wire [DEPTH-1:0] spi_rx; + wire [DEPTH-1:0] spi_tx; + + spi_slave inst_spi_slave0 + ( + .clk(s_axi_aclk), + .rst(s_axi_areset), + + .ss(ss), + .mosi(mosi), + .miso(miso), + .sck(sck), + + .parallel_stb(spi_stb), + .parallel_din(spi_tx), + .parallel_dout(spi_rx) + ); + + wire [7:0] rx_type = spi_rx[7:0]; + + reg [DEPTH-1:0] spi_rx_r0, spi_rx_r1, spi_rx_r2; + always @ (posedge s_axi_aclk) + if (s_axi_areset) begin + spi_rx_r0 <= 64'h0000_0000_0000_0000; + spi_rx_r1 <= 64'h0000_0000_0000_0000; + spi_rx_r2 <= 64'h0000_0000_0000_0000; + end else begin + spi_rx_r0 <= spi_stb && (rx_type == 0) ? spi_rx : spi_rx_r0; + spi_rx_r1 <= spi_stb && (rx_type == 1) ? spi_rx : spi_rx_r1; + spi_rx_r2 <= spi_stb && (rx_type == 2) ? spi_rx : spi_rx_r2; + end + + localparam IDLE = 3'b001; + localparam READ_IN_PROGRESS = 3'b010; + localparam WRITE_IN_PROGRESS = 3'b100; + + reg [2:0] state; + reg [7:0] addr; + + always @ (posedge s_axi_aclk) begin + if (s_axi_areset) begin + state <= IDLE; + end + else case (state) + + IDLE: begin + if (s_axi_arvalid) begin + state <= READ_IN_PROGRESS; + addr <= s_axi_araddr[7:0]; + end + else if (s_axi_awvalid) begin + state <= WRITE_IN_PROGRESS; + addr <= s_axi_awaddr[7:0]; + end + end + + READ_IN_PROGRESS: begin + if (s_axi_rready) + state <= IDLE; + end + + WRITE_IN_PROGRESS: begin + if (s_axi_bready) + state <= IDLE; + end + + default: begin + state <= IDLE; + end + + endcase + end + + // write mux + reg write_shutdown; + reg write_irq_mask; + + always @(*) begin + write_shutdown = 1'b0; + write_irq_mask = 1'b0; + + if (state == WRITE_IN_PROGRESS) + case (addr) + 8'h00: write_shutdown = 1'b1; + 8'h04: write_irq_mask = 1'b1; + endcase + end + + reg [31:0] shutdown = 32'h0000_0000; + always @ (posedge s_axi_aclk) begin + if (s_axi_areset) + shutdown <= 32'h0000_0000; + else if (write_shutdown) + shutdown <= s_axi_wdata; + end + + wire [31:0] spi_tx_tdata; + wire spi_tx_tvalid; + wire [5:0] spi_tx_occupied; + wire [5:0] spi_tx_space; + + wire [31:0] tmux = write_shutdown ? {s_axi_wdata[23:0], 8'h00} + : {s_axi_wdata[7:0], s_axi_wdata[15:8], addr[7:0], 8'h01}; + + wire is_spi_cmd = (addr[7:0] == 8'h00) || (addr[7:0] > 8'h04); + + axi_fifo_bram #(.WIDTH(32), .SIZE(5)) axi_fifo_short_inst + ( + .clk(s_axi_aclk), + .reset(s_axi_areset), + .clear(1'b0), + .i_tdata(tmux), + .i_tvalid(state == WRITE_IN_PROGRESS && is_spi_cmd), + .i_tready(), + .o_tdata(spi_tx_tdata), + .o_tvalid(spi_tx_tvalid), + .o_tready(spi_stb), + .occupied(spi_tx_occupied), + .space(spi_tx_space) + ); + + reg [63:0] spi_tx_reg; + + always @ (posedge s_axi_aclk) + if(s_axi_areset) + spi_tx_reg <= 64'h0000_0000_0000_0000; + else if (spi_stb) + spi_tx_reg <= {spi_tx_tvalid, 31'h00, spi_tx_tdata}; + + assign spi_tx = spi_tx_reg; + + /* battery stuff */ + wire [15:0] battery_voltage = {spi_rx_r0[55:48], spi_rx_r0[63:56]}; + wire [1:0] battery_temp_alert = spi_rx_r0[47:46]; + wire battery_online = spi_rx_r0[45]; + wire [2:0] battery_health = spi_rx_r0[44:42]; + wire [1:0] battery_status = spi_rx_r0[41:40]; + + /* charger stuff */ + /* unused [39:38] */ + wire [1:0] charger_health = spi_rx_r0[37:36]; + wire charger_online = spi_rx_r0[35]; + /* unused bit 34 */ + wire [1:0] charger_charge_type = spi_rx_r0[33:32]; + + /* gauge stuff */ + wire [7:0] gauge_status = spi_rx_r1[63:56]; + wire [15:0] voltage = {spi_rx_r1[47:40], spi_rx_r1[55:48]}; + wire [15:0] temp = {spi_rx_r1[31:24], spi_rx_r1[39:32]}; + wire [15:0] charge_acc = {spi_rx_r1[15:8] , spi_rx_r1[23:16]}; + + /* charge last full */ + wire [15:0] charge_last_full = {spi_rx_r2[15:8], spi_rx_r2[23:16]}; + + /* settings flags */ + wire [7:0] settings = spi_rx_r2[31:24]; + + reg [7:0] irq_enable; + always @ (posedge s_axi_aclk) begin + if (s_axi_areset) + irq_enable <= 8'h00; + else if (write_irq_mask) + irq_enable <= s_axi_wdata[15:8]; + end + + wire [7:0] irq_status = gauge_status; + assign s_axi_irq = |(irq_status & irq_enable); + + wire [3:0] version_maj = spi_rx_r0[15:12]; + wire [3:0] version_min = spi_rx_r0[11:8]; + + reg [31:0] rdata; + // read mux + always @(*) begin + rdata = 32'hdead_beef; + + if (state == READ_IN_PROGRESS) + case (addr) + 8'h00: rdata = shutdown; + 8'h04: rdata = {16'h0000, irq_enable, version_maj, version_min}; + 8'h08: rdata = {8'h0, battery_voltage, battery_temp_alert, battery_online, battery_health, battery_status}; + 8'h0c: rdata = {27'd0, charger_charge_type, charger_online, charger_health}; + 8'h10: rdata = {temp, charge_acc}; + 8'h14: rdata = {8'h00, gauge_status, voltage}; + 8'h18: rdata = {16'h0000, charge_last_full}; + 8'h1c: rdata = {24'd0, settings}; + endcase + end + + assign s_axi_arready = (state == IDLE); + assign s_axi_rvalid = (state == READ_IN_PROGRESS); + assign s_axi_rresp = 2'b00; + + assign s_axi_rdata = rdata; + + assign s_axi_awready = (state == IDLE); + assign s_axi_wready = (state == WRITE_IN_PROGRESS); + assign s_axi_bresp = 2'b00; + assign s_axi_bvalid = (state == WRITE_IN_PROGRESS); + +endmodule |