/* ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio. This file is part of ChibiOS/RT. ChibiOS/RT is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. ChibiOS/RT 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /** * @file pal.c * @brief I/O Ports Abstraction Layer code. * * @addtogroup PAL * @{ */ #include "ch.h" #include "hal.h" #if HAL_USE_PAL || defined(__DOXYGEN__) /*===========================================================================*/ /* Driver exported variables. */ /*===========================================================================*/ /*===========================================================================*/ /* Driver local variables. */ /*===========================================================================*/ /*===========================================================================*/ /* Driver local functions. */ /*===========================================================================*/ /*===========================================================================*/ /* Driver exported functions. */ /*===========================================================================*/ /** * @brief Read from an I/O bus. * @note The operation is not guaranteed to be atomic on all the * architectures, for atomicity and/or portability reasons you may * need to enclose port I/O operations between @p chSysLock() and * @p chSysUnlock(). * @note The function internally uses the @p palReadGroup() macro. The use * of this function is preferred when you value code size, readability * and error checking over speed. * * @param[in] bus the I/O bus, pointer to a @p IOBus structure * @return The bus logical states. * * @api */ ioportmask_t palReadBus(IOBus *bus) { chDbgCheck((bus != NULL) && (bus->bus_offset > PAL_IOPORTS_WIDTH), "palReadBus"); return palReadGroup(bus->bus_portid, bus->bus_mask, bus->bus_offset); } /** * @brief Write to an I/O bus. * @note The operation is not guaranteed to be atomic on all the * architectures, for atomicity and/or portability reasons you may * need to enclose port I/O operations between @p chSysLock() and * @p chSysUnlock(). * @note The default implementation is non atomic and not necessarily * optimal. Low level drivers may optimize the function by using * specific hardware or coding. * * @param[in] bus the I/O bus, pointer to a @p IOBus structure * @param[in] bits the bits to be written on the I/O bus. Values exceeding * the bus width are masked so most significant bits are * lost. * * @api */ void palWriteBus(IOBus *bus, ioportmask_t bits) { chDbgCheck((bus != NULL) && (bus->bus_offset > PAL_IOPORTS_WIDTH), "palWriteBus"); palWriteGroup(bus->bus_portid, bus->bus_mask, bus->bus_offset, bits); } /** * @brief Programs a bus with the specified mode. * @note The operation is not guaranteed to be atomic on all the * architectures, for atomicity and/or portability reasons you may * need to enclose port I/O operations between @p chSysLock() and * @p chSysUnlock(). * @note The default implementation is non atomic and not necessarily * optimal. Low level drivers may optimize the function by using * specific hardware or coding. * * @param[in] bus the I/O bus, pointer to a @p IOBus structure * @param[in] mode the mode * * @api */ void palSetBusMode(IOBus *bus, uint_fast8_t mode) { chDbgCheck((bus != NULL) && (bus->bus_offset > PAL_IOPORTS_WIDTH), "palSetBusMode"); palSetGroupMode(bus->bus_portid, bus->bus_mask, mode); } #endif /* HAL_USE_PAL */ /** @} */ n44'>44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
`default_nettype none

module \$alu (A, B, CI, BI, X, Y, CO);

parameter A_SIGNED = 0;
parameter B_SIGNED = 0;
parameter A_WIDTH = 1;
parameter B_WIDTH = 1;
parameter Y_WIDTH = 1;

parameter _TECHMAP_CONSTMSK_CI_ = 0;
parameter _TECHMAP_CONSTVAL_CI_ = 0;

(* force_downto *)
input [A_WIDTH-1:0] A;
(* force_downto *)
input [B_WIDTH-1:0] B;
input CI, BI;
(* force_downto *)
output [Y_WIDTH-1:0] X, Y, CO;

(* force_downto *)
wire [Y_WIDTH-1:0] A_buf, B_buf;
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));

(* force_downto *)
wire [Y_WIDTH-1:0] AA = A_buf;
(* force_downto *)
wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
(* force_downto *)
wire [Y_WIDTH-1:0] BX = B_buf;
wire [Y_WIDTH:0] ALM_CARRY;

// Start of carry chain
generate
    if (_TECHMAP_CONSTMSK_CI_ == 1) begin
        assign ALM_CARRY[0] = _TECHMAP_CONSTVAL_CI_;
    end else begin
        MISTRAL_ALUT_ARITH #(
            .LUT0(16'b1010_1010_1010_1010), // Q = A
            .LUT1(16'b0000_0000_0000_0000), // Q = 0 (LUT1's input to the adder is inverted)
        ) alm_start (
            .A(CI), .B(1'b1), .C(1'b1), .D0(1'b1), .D1(1'b1),
            .CI(1'b0),
            .CO(ALM_CARRY[0])
        );
    end
endgenerate

// Carry chain
genvar i;
generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice
    // TODO: mwk suggests that a pass could merge pre-adder logic into this.
    MISTRAL_ALUT_ARITH #(
        .LUT0(16'b1010_1010_1010_1010), // Q = A
        .LUT1(16'b1100_0011_1100_0011), // Q = C ? B : ~B (LUT1's input to the adder is inverted)
    ) alm_i (
        .A(AA[i]), .B(BX[i]), .C(BI), .D0(1'b1), .D1(1'b1),
        .CI(ALM_CARRY[i]),
        .SO(Y[i]),
        .CO(ALM_CARRY[i+1])
    );

    // ALM carry chain is not directly accessible, so calculate the carry through soft logic if really needed.
    assign CO[i] = (AA[i] && BB[i]) || ((Y[i] ^ AA[i] ^ BB[i]) && (AA[i] || BB[i]));
end endgenerate

assign X = AA ^ BB;

endmodule