/*
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
|