123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074 |
- // vim: ts=4 sw=4 noexpandtab
- /*
- * Profibus PHY
- *
- * Copyright (c) 2019 Michael Buesch <m@bues.ch>
- *
- * This program 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 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
- `ifndef PROFIBUS_PHY_MOD_V_
- `define PROFIBUS_PHY_MOD_V_
- `include "uart_mod.v"
- `include "spi_slave_mod.v"
- `include "block_ram_mod.v"
- /* Host SPI message format:
- *
- * Data message master to slave:
- * Byte 0 1 2...
- * [0xAA] [FLG] [DATA] ...
- * | | |
- * | | |> from 1 up to 255 Profibus telegram bytes
- * | |> Flags
- * |> Start of message magic constant
- *
- * Data message slave to master:
- * Byte 0 1 2 ... 9 10
- * [0x55] [FLG] [DATA0] ... [DATA7] [LEN]
- * | | | |
- * | | | |> Number of DATA bytes
- * | | |> from 1 up to 8 Profibus telegram bytes
- * | |> Flags
- * |> Start of message magic constant
- *
- * Control message:
- * Byte 0 1 2 3 4 5 6 7
- * [MAGC] [FLG] [CTRL] [DATA0] [DATA1] [DATA2] [DATA3] [CRC]
- * | | | | | | | |
- * | | | | | | | |> CRC-8
- * | | | | | | |> Control data byte 3 (LSB)
- * | | | | | |> Control data byte 2
- * | | | | |> Control data byte 1
- * | | | |> Control data byte 0 (MSB)
- * | | |> Control identifier
- * | |> Flags
- * |> Start of message magic constant.
- * 0xAA if master to slave.
- * 0x55 if slave to master.
- *
- * FLG: bit 7: odd parity of FLG bits 0-6
- * FLG: bit 6: unused (set to 0)
- * FLG: bit 5: unused (set to 0)
- * FLG: bit 4: unused (set to 0)
- * FLG: bit 3: A reset occurred. Get STATUS to see details.
- * FLG: bit 2: New STATUS available
- * FLG: bit 1: Control message
- * FLG: bit 0: Start of telegram
- *
- * CRC polynomial: x^8 + x^2 + x^1 + 1
- *
- * Padding byte: 0x00
- */
- module profibus_telegram_length (
- input clk,
- input n_reset,
- input [7:0] in_byte,
- input new_byte,
- output reg length_valid,
- output reg [7:0] length,
- output reg error,
- );
- localparam STATE_START = 0;
- localparam STATE_LE = 1;
- localparam STATE_LER = 2;
- localparam SD1 = 8'h10;
- localparam SD2 = 8'h68;
- localparam SD3 = 8'hA2;
- localparam SD4 = 8'hDC;
- localparam SC = 8'hE5;
- reg [7:0] byte_le;
- reg [1:0] state;
- initial begin
- length_valid <= 0;
- length <= 0;
- error <= 0;
- byte_le <= 0;
- state <= STATE_START;
- end
- always @(posedge clk) begin
- if (n_reset) begin
- case (state)
- STATE_START: begin
- if (new_byte) begin
- if (in_byte == SD1) begin
- length <= 6;
- error <= 0;
- length_valid <= 1;
- end else if (in_byte == SD2) begin
- length <= 0;
- error <= 0;
- length_valid <= 0;
- state <= STATE_LE;
- end else if (in_byte == SD3) begin
- length <= 14;
- error <= 0;
- length_valid <= 1;
- end else if (in_byte == SD4) begin
- length <= 3;
- error <= 0;
- length_valid <= 1;
- end else if (in_byte == SC) begin
- length <= 1;
- error <= 0;
- length_valid <= 1;
- end else begin
- length <= 0;
- error <= 1;
- length_valid <= 0;
- end
- end
- end
- STATE_LE: begin
- if (new_byte) begin
- if (in_byte >= 4 && in_byte <= 249) begin
- byte_le <= in_byte;
- state <= STATE_LER;
- end else begin
- error <= 1;
- length_valid <= 0;
- state <= STATE_START;
- end
- end
- end
- STATE_LER: begin
- if (new_byte) begin
- if (in_byte == byte_le) begin
- length <= byte_le + 6;
- error <= 0;
- length_valid <= 1;
- state <= STATE_START;
- end else begin
- error <= 1;
- length_valid <= 0;
- state <= STATE_START;
- end
- end
- end
- default: begin
- length_valid <= 0;
- length <= 0;
- error <= 0;
- byte_le <= 0;
- state <= STATE_START;
- end
- endcase
- end else begin
- /* Reset */
- length_valid <= 0;
- length <= 0;
- error <= 0;
- byte_le <= 0;
- state <= STATE_START;
- end
- end
- endmodule
- module profibus_phy #(
- parameter SPI_CPOL = 0, /* SPI clock polarity. Can be 0 or 1. */
- parameter SPI_CPHA = 0, /* SPI clock phase. Can be 0 or 1. */
- parameter SPI_MSB_FIRST = 1, /* MSB transmit first enable. Can be 0 or 1. */
- ) (
- input clk, /* clock */
- input n_reset, /* Not reset */
- /* Host parallel interface: */
- output rx_irq_edge, /* Received data available (edge trigger) */
- output rx_irq_level, /* Received data available (level trigger) */
- /* Host SPI bus interface: */
- input mosi, /* SPI bus MOSI signal */
- output miso, /* SPI bus MISO signal */
- input sck, /* SPI bus clock signal */
- input ss, /* SPI bus slave select signal */
- /* Profibus RS485 bus: */
- input rx, /* Raw receive signal line */
- output rx_active, /* PB receive in progress (optional) */
- output rx_error, /* PB receive error (optional) */
- output tx, /* Raw transmit signal line */
- output tx_active, /* PB transmit in progress (optional) */
- output tx_error, /* PB transmit error (optional) */
- `ifdef DEBUG
- /* Debug interface: */
- output reg debug,
- `endif
- );
- `include "parity_func.v"
- `include "crc8_func.v"
- localparam TXBUF_ADDR_BITS = 8;
- localparam RXBUF_ADDR_BITS = 8;
- /* Start of SPI message magic constant. */
- localparam SPI_MS_MAGIC = 8'hAA; /* Master to slave */
- localparam SPI_SM_MAGIC = 8'h55; /* Slave to master */
- /* SPI message FLG bits */
- localparam SPI_FLG_START = 0;
- localparam SPI_FLG_CTRL = 1;
- localparam SPI_FLG_NEWSTAT = 2;
- localparam SPI_FLG_RESET = 3;
- localparam SPI_FLG_UNUSED4 = 4;
- localparam SPI_FLG_UNUSED5 = 5;
- localparam SPI_FLG_UNUSED6 = 6;
- localparam SPI_FLG_PARITY = 7;
- /* SPI control message IDs. */
- localparam SPICTRL_NOP = 0;
- localparam SPICTRL_PING = 1;
- localparam SPICTRL_PONG = 2;
- localparam SPICTRL_SOFTRESET = 3;
- localparam SPICTRL_GETSTATUS = 4;
- localparam SPICTRL_STATUS = 5;
- localparam SPICTRL_GETBAUD = 6;
- localparam SPICTRL_BAUD = 7;
- /* Status message data bits */
- localparam SPISTAT_PONRESET = 0;
- localparam SPISTAT_HARDRESET = 1;
- localparam SPISTAT_SOFTRESET = 2;
- localparam SPISTAT_TXOVR = 3;
- localparam SPISTAT_RXOVR = 4;
- localparam SPISTAT_CTRLCRCERR = 5;
- /***********************************************************/
- /* General part */
- /***********************************************************/
- /* Power-on-reset, hard-reset and soft-reset status. */
- reg n_poweronreset_status;
- reg n_hardreset_status;
- reg softreset_status;
- /* Soft-reset trigger. */
- reg softreset;
- wire any_reset_status;
- assign any_reset_status = ~n_poweronreset_status | ~n_hardreset_status | softreset_status;
- /* SPICTRL_STATUS should be fetched, if 1. */
- wire new_status_available;
- assign new_status_available = any_reset_status | tx_buf_overflow_get() |
- rx_buf_overflow_get() | spirx_ctrl_crcerr_get();
- initial begin
- n_poweronreset_status <= 0;
- n_hardreset_status <= 0;
- softreset_status <= 0;
- softreset <= 0;
- end
- /***********************************************************/
- /* Data buffer: Profibus transmit buffer */
- /***********************************************************/
- reg [TXBUF_ADDR_BITS - 1 : 0] tx_buf_wr_addr;
- wire [TXBUF_ADDR_BITS - 1 : 0] tx_buf_wr_addr_next;
- reg [7:0] tx_buf_wr_data;
- reg tx_buf_wr;
- reg [TXBUF_ADDR_BITS - 1 : 0] tx_buf_rd_addr;
- wire [7:0] tx_buf_rd_data;
- reg [1:0] tx_buf_overflow;
- block_ram #(
- .ADDR_WIDTH(TXBUF_ADDR_BITS),
- .DATA_WIDTH(8),
- .MEM_BYTES(1 << TXBUF_ADDR_BITS),
- ) tx_buf (
- .clk(clk),
- .addr0(tx_buf_wr_addr),
- .wr_data0(tx_buf_wr_data),
- .wr0(tx_buf_wr),
- .addr1(tx_buf_rd_addr),
- .rd_data1(tx_buf_rd_data),
- );
- assign tx_buf_wr_addr_next = tx_buf_wr_addr + 1;
- initial begin
- tx_buf_wr_addr <= 0;
- tx_buf_wr_data <= 0;
- tx_buf_wr <= 0;
- tx_buf_rd_addr <= 0;
- tx_buf_overflow <= 0;
- end
- function automatic tx_buf_overflow_get;
- begin tx_buf_overflow_get = tx_buf_overflow[0] ^ tx_buf_overflow[1]; end
- endfunction
- task automatic tx_buf_overflow_set;
- begin tx_buf_overflow[0] <= ~tx_buf_overflow[1]; end
- endtask
- task automatic tx_buf_overflow_reset;
- begin tx_buf_overflow[1] <= tx_buf_overflow[0]; end
- endtask
- /***********************************************************/
- /* Data buffer: Profibus receive buffer */
- /***********************************************************/
- localparam RXBUF_SOT_BIT = 8; /* Start-of-telegram marker bit. */
- reg [RXBUF_ADDR_BITS - 1 : 0] rx_buf_wr_addr;
- wire [RXBUF_ADDR_BITS - 1 : 0] rx_buf_wr_addr_next;
- reg [8:0] rx_buf_wr_data;
- reg rx_buf_wr;
- reg [RXBUF_ADDR_BITS - 1 : 0] rx_buf_rd_addr;
- wire [8:0] rx_buf_rd_data;
- reg [1:0] rx_buf_overflow;
- block_ram #(
- .ADDR_WIDTH(RXBUF_ADDR_BITS),
- .DATA_WIDTH(9),
- .MEM_BYTES(1 << RXBUF_ADDR_BITS),
- ) rx_buf (
- .clk(clk),
- .addr0(rx_buf_wr_addr),
- .wr_data0(rx_buf_wr_data),
- .wr0(rx_buf_wr),
- .addr1(rx_buf_rd_addr),
- .rd_data1(rx_buf_rd_data),
- );
- assign rx_buf_wr_addr_next = rx_buf_wr_addr + 1;
- initial begin
- rx_buf_wr_addr <= 0;
- rx_buf_wr_data <= 0;
- rx_buf_wr <= 0;
- rx_buf_rd_addr <= 0;
- rx_buf_overflow <= 0;
- end
- function automatic rx_buf_overflow_get;
- begin rx_buf_overflow_get = rx_buf_overflow[0] ^ rx_buf_overflow[1]; end
- endfunction
- task automatic rx_buf_overflow_set;
- begin rx_buf_overflow[0] <= ~rx_buf_overflow[1]; end
- endtask
- task automatic rx_buf_overflow_reset;
- begin rx_buf_overflow[1] <= rx_buf_overflow[0]; end
- endtask
- /***********************************************************/
- /* UART module */
- /***********************************************************/
- wire uart_rx_irq;
- wire [7:0] uart_rx_data;
- wire uart_rx_parity_ok;
- wire uart_rx_frame_error;
- wire uart_rx_active;
- wire uart_tx_irq;
- wire uart_tx_active;
- wire uart_tx_pending;
- reg [7:0] uart_tx_data;
- reg uart_tx_trigger;
- reg [23:0] uart_clks_per_sym;
- uart_half_duplex #(
- .DATABITS(8),
- .PARITY_EVEN(1),
- .STOP(1),
- .ACTIVE_LOW(0),
- ) uart (
- .clk(clk),
- .n_reset(n_reset),
- .clks_per_sym(uart_clks_per_sym),
- .rx(rx),
- .rx_irq(uart_rx_irq),
- .rx_active(uart_rx_active),
- .rx_data(uart_rx_data),
- .rx_parity_ok(uart_rx_parity_ok),
- .rx_frame_error(uart_rx_frame_error),
- .tx(tx),
- .tx_irq(uart_tx_irq),
- .tx_active(uart_tx_active),
- .tx_pending(uart_tx_pending),
- .tx_data(uart_tx_data),
- .tx_trigger(uart_tx_trigger),
- );
- assign rx_active = uart_rx_active;
- assign rx_error = ~uart_rx_parity_ok | uart_rx_frame_error;
- assign tx_active = uart_tx_active;
- assign tx_error = spirx_lencalc_error;
- initial begin
- uart_tx_data <= 0;
- uart_tx_trigger <= 0;
- uart_clks_per_sym <= 0;
- end
- /***********************************************************/
- /* SPI module */
- /***********************************************************/
- wire spi_rx_irq;
- wire spi_tx_irq;
- wire [7:0] spi_rx_data;
- reg [7:0] spi_tx_data;
- spi_slave #(
- .WORDSIZE(8),
- .CPOL(SPI_CPOL),
- .CPHA(SPI_CPHA),
- .MSB_FIRST(SPI_MSB_FIRST),
- ) spi (
- .clk(clk),
- .mosi(mosi),
- .miso(miso),
- .sck(sck),
- .ss(ss),
- .rx_irq(spi_rx_irq),
- .rx_data(spi_rx_data),
- .tx_data(spi_tx_data),
- );
- assign spi_tx_irq = spi_rx_irq;
- initial begin
- spi_tx_data <= 0;
- end
- /***********************************************************/
- /* UART receive */
- /* This process receives data from the Profibus line */
- /* and puts it into the Profibus receive buffer. */
- /***********************************************************/
- reg [23:0] tsyn_clks;
- /* Receive interrupts */
- assign rx_irq_edge = rx_buf_wr;
- assign rx_irq_level = rx_buf_wr | (rx_buf_wr_addr != rx_buf_rd_addr);
- initial begin
- tsyn_clks <= 0;
- end
- always @(posedge clk) begin
- if (n_reset & ~softreset) begin
- if (uart_rx_irq) begin
- if (uart_rx_parity_ok & ~uart_rx_frame_error) begin
- if (rx_buf_wr_addr_next != rx_buf_rd_addr) begin
- rx_buf_wr_data[7:0] <= uart_rx_data;
- /* Start-of-telegram bit. */
- rx_buf_wr_data[RXBUF_SOT_BIT] <= (timer_idle_saved >= tsyn_clks);
- rx_buf_wr <= 1;
- end else begin
- /* RX buffer overflow. */
- rx_buf_overflow_set();
- end
- end
- end else begin
- if (rx_buf_wr) begin
- rx_buf_wr <= 0;
- rx_buf_wr_addr <= rx_buf_wr_addr_next;
- end
- end
- end else begin
- /* Reset */
- rx_buf_wr <= 0;
- rx_buf_wr_addr <= 0;
- end
- end
- /***********************************************************/
- /* UART transmit. */
- /* This process transmits data to the Profibus line */
- /* from the Profibus transmit buffer. */
- /***********************************************************/
- always @(posedge clk) begin
- if (n_reset & ~softreset) begin
- if (uart_tx_trigger) begin
- uart_tx_trigger <= 0;
- end else begin
- /* Check if new TX data is pending. */
- if (tx_buf_rd_addr != tx_buf_wr_addr) begin
- /* Check if we are able to transmit. */
- if (~uart_tx_active & ~uart_tx_pending) begin
- /* Transmit the byte to the PB line. */
- uart_tx_data <= tx_buf_rd_data;
- uart_tx_trigger <= 1;
- tx_buf_rd_addr <= tx_buf_rd_addr + 1;
- end
- end
- end
- end else begin
- /* Reset */
- uart_tx_data <= 0;
- uart_tx_trigger <= 0;
- tx_buf_rd_addr <= 0;
- end
- end
- /***********************************************************/
- /* SPI receive. */
- /* This process receives data from the host SPI bus */
- /* and puts it into the Profibus transmit buffer. */
- /***********************************************************/
- localparam SPIRX_BEGIN = 0;
- localparam SPIRX_FLG = 1;
- localparam SPIRX_DATA = 2;
- localparam SPIRX_CTRL = 3;
- localparam SPIRX_CTRL_DATA = 4;
- localparam SPIRX_CRC = 5;
- localparam SPIRX_CTRL_EXEC = 6;
- reg [2:0] spirx_state;
- reg [7:0] spirx_len;
- reg spirx_len_valid;
- reg [7:0] spirx_bytecount;
- reg [7:0] spirx_ctrl;
- reg [31:0] spirx_ctrl_data;
- reg [7:0] spirx_crc;
- reg [1:0] spirx_ctrl_crcerr;
- /* Length calculation of PB frames. */
- wire spirx_lencalc_n_reset_wire;
- reg spirx_lencalc_n_reset;
- reg [7:0] spirx_lencalc_byte;
- reg spirx_lencalc_new;
- wire spirx_lencalc_valid;
- wire [7:0] spirx_lencalc_length;
- wire spirx_lencalc_error;
- profibus_telegram_length spirx_lencalc (
- .clk(clk),
- .n_reset(spirx_lencalc_n_reset_wire),
- .in_byte(spirx_lencalc_byte),
- .new_byte(spirx_lencalc_new),
- .length_valid(spirx_lencalc_valid),
- .length(spirx_lencalc_length),
- .error(spirx_lencalc_error),
- );
- assign spirx_lencalc_n_reset_wire = spirx_lencalc_n_reset & ~softreset & n_reset;
- initial begin
- spirx_state <= SPIRX_BEGIN;
- spirx_len <= 0;
- spirx_len_valid <= 0;
- spirx_bytecount <= 0;
- spirx_ctrl <= 0;
- spirx_ctrl_data <= 0;
- spirx_crc <= 0;
- spirx_ctrl_crcerr <= 0;
- spirx_lencalc_n_reset <= 0;
- spirx_lencalc_byte <= 0;
- spirx_lencalc_new <= 0;
- end
- function automatic spirx_ctrl_crcerr_get;
- begin spirx_ctrl_crcerr_get = spirx_ctrl_crcerr[0] ^ spirx_ctrl_crcerr[1]; end
- endfunction
- task automatic spirx_ctrl_crcerr_set;
- begin spirx_ctrl_crcerr[0] <= ~spirx_ctrl_crcerr[1]; end
- endtask
- task automatic spirx_ctrl_crcerr_reset;
- begin spirx_ctrl_crcerr[1] <= spirx_ctrl_crcerr[0]; end
- endtask
- always @(posedge clk) begin
- if (n_reset & ~softreset) begin
- case (spirx_state)
- SPIRX_BEGIN: begin
- /* Wait for start of SPI receive. */
- if (spi_rx_irq) begin
- if (spi_rx_data == SPI_MS_MAGIC) begin
- spirx_ctrl <= 0;
- spirx_ctrl_data <= 0;
- spirx_len <= 0;
- spirx_len_valid <= 0;
- spirx_crc <= 8'hFF;
- spirx_state <= SPIRX_FLG;
- end
- end
- if (tx_buf_wr) begin
- tx_buf_wr_addr <= tx_buf_wr_addr + 1;
- tx_buf_wr <= 0;
- end
- spirx_lencalc_byte <= 0;
- spirx_lencalc_new <= 0;
- spirx_lencalc_n_reset <= 0;
- end
- SPIRX_FLG: begin
- /* Flags field. */
- if (spi_rx_irq) begin
- /* Check the FLG checksum. */
- if (parity8(ODD,
- spi_rx_data[0],
- spi_rx_data[1],
- spi_rx_data[2],
- spi_rx_data[3],
- spi_rx_data[4],
- spi_rx_data[5],
- spi_rx_data[6],
- spi_rx_data[7]) == 0) begin
- if (spi_rx_data[SPI_FLG_CTRL]) begin
- /* We have a control message. */
- spirx_bytecount <= 0;
- spirx_state <= SPIRX_CTRL;
- end else begin
- /* Begin PB data. */
- spirx_lencalc_n_reset <= 1;
- spirx_bytecount <= 0;
- spirx_state <= SPIRX_DATA;
- end
- end else begin
- /* Incorrect checksum. */
- spirx_state <= SPIRX_BEGIN;
- end
- end
- end
- SPIRX_DATA: begin
- /* Receive data bytes. */
- if (spirx_len_valid) begin
- /* spirx_len is valid.
- * Check if we received all bytes. */
- if (spirx_bytecount >= spirx_len) begin
- spirx_state <= SPIRX_BEGIN;
- end
- end else begin
- /* Try to calculate the telegram length. */
- spirx_lencalc_byte <= spi_rx_data;
- spirx_lencalc_new <= spi_rx_irq;
- if (spirx_lencalc_error) begin
- /* Failed to calculate the length. Abort. */
- spirx_lencalc_n_reset <= 0;
- spirx_state <= SPIRX_BEGIN;
- end else if (spirx_lencalc_valid) begin
- /* Successfully calculated the data length. */
- spirx_len <= spirx_lencalc_length;
- spirx_len_valid <= 1;
- spirx_lencalc_n_reset <= 0;
- end
- end
- if (tx_buf_wr) begin
- /* Increment TX buffer pointer. */
- tx_buf_wr_addr <= tx_buf_wr_addr + 1;
- tx_buf_wr <= 0;
- end else begin
- /* Did we receive a byte? */
- if (spi_rx_irq) begin
- if (tx_buf_wr_addr_next != tx_buf_rd_addr) begin
- /* Put the new byte into the TX buffer. */
- tx_buf_wr_data <= spi_rx_data;
- tx_buf_wr <= 1;
- spirx_bytecount <= spirx_bytecount + 1;
- end else begin
- /* TX buffer overflow. */
- tx_buf_overflow_set();
- spirx_bytecount <= spirx_bytecount + 1;
- end
- end
- end
- end
- SPIRX_CTRL: begin
- /* Receive control command byte. */
- if (spi_rx_irq) begin
- spirx_ctrl <= spi_rx_data;
- spirx_crc <= crc8(spirx_crc, spi_rx_data);
- spirx_state <= SPIRX_CTRL_DATA;
- end
- end
- SPIRX_CTRL_DATA: begin
- /* Receive control data bytes. */
- if (spi_rx_irq) begin
- spirx_ctrl_data <= (spirx_ctrl_data << 8) | spi_rx_data;
- spirx_crc <= crc8(spirx_crc, spi_rx_data);
- if (spirx_bytecount >= 4 - 1) begin
- spirx_state <= SPIRX_CRC;
- end
- spirx_bytecount <= spirx_bytecount + 1;
- end
- end
- SPIRX_CRC: begin
- /* Receive CRC byte. */
- if (spi_rx_irq) begin
- if (spi_rx_data == spirx_crc) begin
- spirx_state <= SPIRX_CTRL_EXEC;
- end else begin
- /* Incorrect CRC. Do not run the control command. */
- spirx_ctrl_crcerr_set();
- spirx_state <= SPIRX_BEGIN;
- end
- end
- end
- SPIRX_CTRL_EXEC: begin
- /* Handle received control message. */
- case (spirx_ctrl)
- SPICTRL_NOP: begin
- /* NOP command. Do nothing. */
- spirx_state <= SPIRX_BEGIN;
- end
- SPICTRL_PING: begin
- /* PING command. Send PONG. */
- if (spitx_ctrl_pending == spitx_ctrl_pending_ack) begin
- spitx_ctrl_reply <= SPICTRL_PONG;
- spitx_ctrl_reply_data <= 0;
- spitx_ctrl_pending <= ~spitx_ctrl_pending_ack;
- spirx_state <= SPIRX_BEGIN;
- end
- end
- SPICTRL_PONG: begin
- /* Ignore. */
- spirx_state <= SPIRX_BEGIN;
- end
- SPICTRL_SOFTRESET: begin
- /* Trigger a soft reset. */
- softreset <= 1;
- spirx_state <= SPIRX_BEGIN;
- end
- SPICTRL_GETSTATUS: begin
- if (spitx_ctrl_pending == spitx_ctrl_pending_ack) begin
- spitx_ctrl_reply <= SPICTRL_STATUS;
- spitx_ctrl_reply_data[SPISTAT_PONRESET] <= ~n_poweronreset_status;
- spitx_ctrl_reply_data[SPISTAT_HARDRESET] <= ~n_hardreset_status;
- spitx_ctrl_reply_data[SPISTAT_SOFTRESET] <= softreset_status;
- spitx_ctrl_reply_data[SPISTAT_TXOVR] <= tx_buf_overflow_get();
- spitx_ctrl_reply_data[SPISTAT_RXOVR] <= rx_buf_overflow_get();
- spitx_ctrl_reply_data[SPISTAT_CTRLCRCERR] <= spirx_ctrl_crcerr_get();
- spitx_ctrl_reply_data[31:6] <= 0;
- spitx_ctrl_pending <= ~spitx_ctrl_pending_ack;
- /* Reset all error states. */
- tx_buf_overflow_reset();
- rx_buf_overflow_reset();
- spirx_ctrl_crcerr_reset();
- /* Reset all reset status bits */
- n_poweronreset_status <= 1;
- n_hardreset_status <= 1;
- softreset_status <= 0;
- spirx_state <= SPIRX_BEGIN;
- end
- end
- SPICTRL_STATUS: begin
- /* Ignore. */
- spirx_state <= SPIRX_BEGIN;
- end
- SPICTRL_GETBAUD: begin
- if (spitx_ctrl_pending == spitx_ctrl_pending_ack) begin
- spitx_ctrl_reply <= SPICTRL_BAUD;
- spitx_ctrl_reply_data[31:24] <= 0;
- spitx_ctrl_reply_data[23:0] <= spirx_ctrl_data[23:0];
- spitx_ctrl_pending <= ~spitx_ctrl_pending_ack;
- spirx_state <= SPIRX_BEGIN;
- end
- end
- SPICTRL_BAUD: begin
- if (spitx_ctrl_pending == spitx_ctrl_pending_ack) begin
- spitx_ctrl_reply <= SPICTRL_BAUD;
- spitx_ctrl_reply_data[31:24] <= 0;
- spitx_ctrl_reply_data[23:0] <= spirx_ctrl_data[23:0];
- spitx_ctrl_pending <= ~spitx_ctrl_pending_ack;
- /* Set the new baud rate. */
- uart_clks_per_sym[23:0] <= spirx_ctrl_data[23:0];
- /* Set the new TSYN timing.
- * The number of TSYN clks is:
- * clks_per_symbol * 33
- */
- tsyn_clks <= (spirx_ctrl_data[23:0] << 5) + spirx_ctrl_data[23:0];
- spirx_state <= SPIRX_BEGIN;
- end
- end
- default: begin
- /* Unknown control command. */
- spirx_state <= SPIRX_BEGIN;
- end
- endcase
- end
- default: begin
- /* Invalid case. */
- spirx_ctrl <= 0;
- spirx_ctrl_data <= 0;
- tx_buf_wr_addr <= 0;
- tx_buf_wr_data <= 0;
- tx_buf_wr <= 0;
- spirx_state <= SPIRX_BEGIN;
- spirx_lencalc_n_reset <= 0;
- end
- endcase
- end else begin
- /* Reset */
- spirx_ctrl <= 0;
- spirx_ctrl_data <= 0;
- tx_buf_wr_addr <= 0;
- tx_buf_wr_data <= 0;
- tx_buf_wr <= 0;
- spirx_state <= SPIRX_BEGIN;
- spirx_lencalc_n_reset <= 0;
- rx_buf_overflow_reset();
- tx_buf_overflow_reset();
- spirx_ctrl_crcerr_reset();
- softreset_status <= softreset;
- n_hardreset_status <= n_reset;
- n_poweronreset_status <= 1;
- softreset <= 0;
- end
- end
- /***********************************************************/
- /* SPI transmit. */
- /* This process transmits data to the host SPI bus */
- /* from the Profibus receive buffer. */
- /***********************************************************/
- reg [7:0] spitx_ctrl_reply;
- reg [31:0] spitx_ctrl_reply_data;
- reg spitx_ctrl_pending;
- reg spitx_ctrl_pending_ack;
- reg [7:0] spitx_bytecount;
- reg [7:0] spitx_len;
- reg spitx_tail;
- reg spitx_ctrl_running;
- reg spitx_data_running;
- reg [7:0] spitx_crc;
- initial begin
- spitx_ctrl_reply <= 0;
- spitx_ctrl_reply_data <= 0;
- spitx_ctrl_pending <= 0;
- spitx_ctrl_pending_ack <= 0;
- spitx_bytecount <= 0;
- spitx_len <= 0;
- spitx_ctrl_running <= 0;
- spitx_data_running <= 0;
- spitx_crc <= 0;
- end
- always @(posedge clk) begin
- if (n_reset & ~softreset) begin
- /* Are we currently not transmitting a data frame
- * and is a control frame pending? */
- if (~spitx_data_running &&
- spitx_ctrl_pending != spitx_ctrl_pending_ack) begin
- if (spi_tx_irq) begin
- case (spitx_bytecount)
- 0: begin
- spi_tx_data <= SPI_SM_MAGIC;
- spitx_bytecount <= spitx_bytecount + 1;
- spitx_ctrl_running <= 1;
- end
- 1: begin
- spi_tx_data[SPI_FLG_START] <= 0;
- spi_tx_data[SPI_FLG_CTRL] <= 1;
- spi_tx_data[SPI_FLG_NEWSTAT] <= new_status_available;
- spi_tx_data[SPI_FLG_RESET] <= any_reset_status;
- spi_tx_data[SPI_FLG_UNUSED4] <= 0;
- spi_tx_data[SPI_FLG_UNUSED5] <= 0;
- spi_tx_data[SPI_FLG_UNUSED6] <= 0;
- spi_tx_data[SPI_FLG_PARITY] <= parity8(ODD, 0,
- 0,
- 1,
- new_status_available,
- any_reset_status,
- 0,
- 0,
- 0);
- spitx_crc <= 8'hFF;
- spitx_bytecount <= spitx_bytecount + 1;
- spitx_ctrl_running <= 1;
- end
- 2: begin
- spi_tx_data <= spitx_ctrl_reply;
- spitx_crc <= crc8(spitx_crc, spitx_ctrl_reply);
- spitx_bytecount <= spitx_bytecount + 1;
- spitx_ctrl_running <= 1;
- end
- 3: begin
- spi_tx_data <= spitx_ctrl_reply_data[31:24];
- spitx_crc <= crc8(spitx_crc, spitx_ctrl_reply_data[31:24]);
- spitx_bytecount <= spitx_bytecount + 1;
- spitx_ctrl_running <= 1;
- end
- 4: begin
- spi_tx_data <= spitx_ctrl_reply_data[23:16];
- spitx_crc <= crc8(spitx_crc, spitx_ctrl_reply_data[23:16]);
- spitx_bytecount <= spitx_bytecount + 1;
- spitx_ctrl_running <= 1;
- end
- 5: begin
- spi_tx_data <= spitx_ctrl_reply_data[15:8];
- spitx_crc <= crc8(spitx_crc, spitx_ctrl_reply_data[15:8]);
- spitx_bytecount <= spitx_bytecount + 1;
- spitx_ctrl_running <= 1;
- end
- 6: begin
- spi_tx_data <= spitx_ctrl_reply_data[7:0];
- spitx_crc <= crc8(spitx_crc, spitx_ctrl_reply_data[7:0]);
- spitx_bytecount <= spitx_bytecount + 1;
- spitx_ctrl_running <= 1;
- end
- 7: begin
- spi_tx_data <= spitx_crc;
- spitx_bytecount <= 0;
- spitx_ctrl_running <= 0;
- spitx_ctrl_pending_ack <= spitx_ctrl_pending;
- end
- default: begin
- spitx_bytecount <= 0;
- spitx_ctrl_running <= 0;
- spitx_ctrl_pending_ack <= spitx_ctrl_pending;
- end
- endcase
- end
- /* Are we currently not transmitting a control frame
- * and is a data frame pending? */
- end else if ((~spitx_ctrl_running &&
- rx_buf_wr_addr != rx_buf_rd_addr) ||
- spitx_data_running) begin
- if (spi_tx_irq) begin
- /* We have a new PB telegram byte. Send it to the host. */
- if (spitx_bytecount == 0) begin
- spi_tx_data <= SPI_SM_MAGIC;
- spitx_bytecount <= spitx_bytecount + 1;
- spitx_len <= 0;
- spitx_tail <= 0;
- spitx_data_running <= 1;
- end else if (spitx_bytecount == 1) begin
- spi_tx_data[SPI_FLG_START] = rx_buf_rd_data[RXBUF_SOT_BIT];
- spi_tx_data[SPI_FLG_CTRL] = 0;
- spi_tx_data[SPI_FLG_NEWSTAT] = new_status_available;
- spi_tx_data[SPI_FLG_RESET] = any_reset_status;
- spi_tx_data[SPI_FLG_UNUSED4] = 0;
- spi_tx_data[SPI_FLG_UNUSED5] = 0;
- spi_tx_data[SPI_FLG_UNUSED6] = 0;
- spi_tx_data[SPI_FLG_PARITY] = parity8(ODD, 0,
- rx_buf_rd_data[RXBUF_SOT_BIT],
- 0,
- new_status_available,
- any_reset_status,
- 0,
- 0,
- 0);
- spitx_bytecount <= spitx_bytecount + 1;
- spitx_data_running <= 1;
- end else if (spitx_bytecount >= 2 && spitx_bytecount <= 9) begin
- if (spitx_tail ||
- (rx_buf_wr_addr == rx_buf_rd_addr) ||
- (spitx_bytecount >= 3 && rx_buf_rd_data[RXBUF_SOT_BIT])) begin
- spi_tx_data <= 0;
- spitx_bytecount <= spitx_bytecount + 1;
- spitx_tail <= 1;
- end else begin
- spi_tx_data <= rx_buf_rd_data;
- rx_buf_rd_addr <= rx_buf_rd_addr + 1;
- spitx_bytecount <= spitx_bytecount + 1;
- spitx_len <= spitx_len + 1;
- end
- spitx_data_running <= 1;
- end else begin
- spi_tx_data <= spitx_len;
- spitx_bytecount <= 0;
- spitx_data_running <= 0;
- end
- end
- end else begin
- /* No frame pending. */
- if (spi_tx_irq) begin
- spi_tx_data <= 0;
- end
- spitx_bytecount <= 0;
- spitx_data_running <= 0;
- spitx_ctrl_running <= 0;
- end
- end else begin
- /* Reset. */
- spi_tx_data <= 0;
- spitx_bytecount <= 0;
- spitx_len <= 0;
- spitx_tail <= 0;
- spitx_ctrl_running <= 0;
- spitx_data_running <= 0;
- spitx_ctrl_pending_ack <= spitx_ctrl_pending;
- spitx_crc <= 0;
- end
- end
- /***********************************************************/
- /* PB timekeeping. */
- /***********************************************************/
- reg timer_idle_active;
- reg [23:0] timer_idle;
- reg [23:0] timer_idle_saved;
- localparam TIMER_MAX = 24'hFFFFFF;
- initial begin
- timer_idle_active <= 0;
- timer_idle <= 0;
- timer_idle_saved <= TIMER_MAX;
- end
- always @(posedge clk) begin
- if (n_reset & ~softreset) begin
- if (uart_tx_active | uart_tx_irq |
- uart_rx_active | uart_rx_irq) begin
- /* A PB transmission is active. Reset idle timer. */
- if (timer_idle_active) begin
- timer_idle_saved <= timer_idle;
- end
- timer_idle_active <= 0;
- timer_idle <= 0;
- end else begin
- /* PB is idle, increment the idle timer. Avoid overflow. */
- if (timer_idle < TIMER_MAX) begin
- timer_idle <= timer_idle + 1;
- end
- timer_idle_active <= 1;
- end
- end else begin
- timer_idle_active <= 0;
- timer_idle <= 0;
- timer_idle_saved <= TIMER_MAX;
- end
- end
- endmodule
- `endif /* PROFIBUS_PHY_MOD_V_ */
|