記事サポート
2022年10月11日
Interface編集部
ethercat_core
↓RTLコードはこちら
↓RTLコードはこちら
↓RTLコードはこちら
↓RTLコードはこちら
`default_nettype none
// ESC register
// | Name | Address | Length | R/W | Init Value | Note |
// | :---------------------------------- | :------ | --------: | :--- | -----------------: | :---------------------- |
// | ESC Information | 0x0000 | 2 Bytes | R | 0x0000 | |
// | Configured Station Address | 0x0010 | 2 Bytes | R/W | 0x0000 | |
// | Configured Station Alias | 0x0012 | 2 Bytes | R/W | 0x0000 | |
// | ESC DL Control | 0x0100 | 4 Bytes | R/W | 0x00000000 | Not used |
// | AL Control | 0x0120 | 2 Bytes | R/W | 0x0000 | |
// | AL Status | 0x0130 | 4 Bytes | R | 0x00000001 | |
// | EEPROM Configuration | 0x0500 | 1 Byte | R/W | 0x00 | Not used |
// | EEPROM PDI Access State | 0x0501 | 1 Byte | R/W | 0x00 | Not used |
// | EEPROM Control/Status | 0x0502 | 2 Bytes | R/W | 0x0000 | |
// | EEPROM Address | 0x0504 | 4 Bytes | R/W | 0x0000 | |
// | EEPROM Data | 0x0508 | 4 Bytes | R | 0x0000 | |
// | FMMU 0 | 0x0600 | 16 Bytes | R/W | All zeros | |
// | FMMU 1 | 0x0610 | 16 Bytes | R/W | All zeros | |
// | Sync Manager 0 | 0x0800 | 8 Bytes | R/W | All zeros | |
// | Sync Manager 1 | 0x0808 | 8 Bytes | R/W | All zeros | |
module ethercat_core # (
parameter ETH_PORT_NUM = 1
) (
input wire clk,
input wire rst,
// GPIO
input wire [31:0] gpio_in,
output logic [31:0] gpio_out,
// Pseudo EEPROM
output logic [31:0] eeprom_address,
input wire [31:0] eeprom_data,
// AXI4-Stream input
input wire [7:0] s_axis_tdata,
input wire s_axis_tvalid,
output logic s_axis_tready,
input wire s_axis_tlast,
// AXI4-Stream output
output logic [7:0] m_axis_tdata,
output logic m_axis_tvalid,
input wire m_axis_tready,
output logic m_axis_tlast
);
// GPIO connections
logic [31:0] sync_manager_in[2];
logic [31:0] sync_manager_out[2];
assign sync_manager_in[0] = gpio_out;
assign sync_manager_in[1] = gpio_in;
assign gpio_out = sync_manager_out[0];
// AXI4-Stream handshake
assign s_axis_tready = m_axis_tready | ~m_axis_tvalid;
// Internal AXI4-Stream
logic [7:0] int_axis_tdata;
logic int_axis_tvalid;
logic int_axis_tlast;
// Application Layer (AL) status parameters
localparam [7:0] AL_STATUS_INIT = 8'h01;
localparam [7:0] AL_STATUS_PRE_OP = 8'h02;
localparam [7:0] AL_STATUS_SAFE_OP = 8'h04;
localparam [7:0] AL_STATUS_OP = 8'h08;
localparam [15:0] AL_STATUS_CODE = 16'h0000;
// Address parameters
localparam ADDR_ESC_INFORMATION = 16'h0000;
localparam ADDR_CONFIGURED_STATION_ADDRESS = 16'h0010;
localparam ADDR_CONFIGURED_STATION_ALIAS = 16'h0012;
localparam ADDR_ESC_DL_CONTROL = 16'h0100;
localparam ADDR_AL_CONTROL = 16'h0120;
localparam ADDR_AL_STATUS = 16'h0130;
localparam ADDR_EEPROM_CONFIGURATION = 16'h0500;
localparam ADDR_EEPROM_PDI_ACCESS_STATE = 16'h0501;
localparam ADDR_EEPROM_CONTROL_STATUS = 16'h0502;
localparam ADDR_EEPROM_ADDRESS = 16'h0504;
localparam ADDR_EEPROM_DATA = 16'h0508;
localparam ADDR_FMMU_0 = 16'h0600;
localparam ADDR_FMMU_1 = 16'h0610;
localparam ADDR_SYNC_MANAGER_0 = 16'h0800;
localparam ADDR_SYNC_MANAGER_1 = 16'h0808;
// Capture the following information from the EtherCAT datagram header:
// - Command ( 8 bits)
// - Index ( 8 bits)
// - Slave Address (16 bits)
// - Offset Address (16 bits)
// - Logical Address (32 bits)
// - Length (11 bits)
// - Circulating ( 1 bit)
// - Next ( 1 bit)
// - IRQ (16 bits)
logic [ 7:0] ethercat_datagram_command;
logic [ 7:0] ethercat_datagram_index;
logic [15:0] ethercat_datagram_slave_address;
logic [15:0] ethercat_datagram_offset_address;
wire [31:0] ethercat_datagram_logical_address = {ethercat_datagram_slave_address, ethercat_datagram_offset_address};
logic [10:0] ethercat_datagram_length;
logic ethercat_datagram_circulating;
logic ethercat_datagram_next;
logic [15:0] ethercat_datagram_irq;
always_ff @(posedge clk) begin
if (rst) begin
ethercat_datagram_length <= 'd0;
end else begin
if (s_axis_tvalid & s_axis_tready) begin
case (ethercat_datagram_counter[0])
'd0: ethercat_datagram_command <= s_axis_tdata;
'd1: ethercat_datagram_index <= s_axis_tdata;
'd2: ethercat_datagram_slave_address[7:0] <= s_axis_tdata;
'd3: ethercat_datagram_slave_address[15:8] <= s_axis_tdata;
'd4: ethercat_datagram_offset_address[7:0] <= s_axis_tdata;
'd5: ethercat_datagram_offset_address[15:8] <= s_axis_tdata;
'd6: ethercat_datagram_length[7:0] <= s_axis_tdata;
'd7: begin
ethercat_datagram_length[10:8] <= s_axis_tdata[2:0];
ethercat_datagram_circulating <= s_axis_tdata[6];
ethercat_datagram_next <= s_axis_tdata[7];
end
'd8: ethercat_datagram_irq[7:0] <= s_axis_tdata;
'd9: ethercat_datagram_irq[15:8] <= s_axis_tdata;
default: ;
endcase
end
end
end
// Detect EtherCAT datagram command
localparam CMD_APRD = 1;
localparam CMD_APWR = 2;
localparam CMD_APRW = 3;
localparam CMD_FPRD = 4;
localparam CMD_FPWR = 5;
localparam CMD_FPRW = 6;
localparam CMD_BRD = 7;
localparam CMD_BWR = 8;
localparam CMD_BRW = 9;
localparam CMD_LRD = 10;
localparam CMD_LWR = 11;
localparam CMD_LRW = 12;
localparam CMD_ARMW = 13; // Not supported
localparam CMD_FRMW = 14; // Not supported
logic valid_address, logical_address, write_req, read_req, auto_increment, broadcast;
wire read_write = write_req & read_req;
always_comb begin
valid_address = 1'b0;
logical_address = 1'b0;
write_req = 1'b0;
read_req = 1'b0;
auto_increment = 1'b0;
broadcast = 1'b0;
case (ethercat_datagram_command)
CMD_APRD: begin
valid_address = (ethercat_datagram_slave_address == 16'h0000);
read_req = 1'b1;
auto_increment = 1'b1;
end
CMD_APWR: begin
valid_address = (ethercat_datagram_slave_address == 16'h0000);
write_req = 1'b1;
auto_increment = 1'b1;
end
CMD_APRW: begin
valid_address = (ethercat_datagram_slave_address == 16'h0000);
read_req = 1'b1;
write_req = 1'b1;
auto_increment = 1'b1;
end
CMD_FPRD: begin
valid_address = (ethercat_datagram_slave_address == configured_station_address);
read_req = 1'b1;
end
CMD_FPWR: begin
valid_address = (ethercat_datagram_slave_address == configured_station_address);
write_req = 1'b1;
end
CMD_FPRW: begin
valid_address = (ethercat_datagram_slave_address == configured_station_address);
read_req = 1'b1;
write_req = 1'b1;
end
CMD_BRD: begin
valid_address = 1'b1;
read_req = 1'b1;
broadcast = 1'b1;
end
CMD_BWR: begin
valid_address = 1'b1;
write_req = 1'b1;
broadcast = 1'b1;
end
CMD_BRW: begin
valid_address = 1'b1;
read_req = 1'b1;
write_req = 1'b1;
broadcast = 1'b1;
end
CMD_LRD: begin
valid_address = 1'b1;
logical_address = 1'b1;
read_req = 1'b1;
end
CMD_LWR: begin
valid_address = 1'b1;
logical_address = 1'b1;
write_req = 1'b1;
end
CMD_LRW: begin
valid_address = 1'b1;
logical_address = 1'b1;
read_req = 1'b1;
write_req = 1'b1;
end
default: ;
endcase
end
// Rewrite the EtherCAT datagram data
logic calculate_carry;
always_ff @(posedge clk) begin
if (rst) begin
int_axis_tvalid <= 1'b0;
m_axis_tvalid <= 1'b0;
end else begin
if (s_axis_tready) begin
int_axis_tdata <= s_axis_tdata;
int_axis_tvalid <= s_axis_tvalid;
int_axis_tlast <= s_axis_tlast;
m_axis_tdata <= int_axis_tdata;
m_axis_tvalid <= int_axis_tvalid;
m_axis_tlast <= int_axis_tlast;
if (auto_increment) begin
if (ethercat_datagram_slave_address_region_upper) begin
int_axis_tdata <= s_axis_tdata + {7'd0, calculate_carry};
end else if (ethercat_datagram_slave_address_region_lower) begin
{calculate_carry, int_axis_tdata} <= {1'd0, s_axis_tdata} + 'd1;
end
end
if (valid_address) begin
if (ethercat_datagram_data_region[1]) begin
if (read_req & read_en) begin
if (broadcast) begin
m_axis_tdata <= read_data | int_axis_tdata;
end else begin
m_axis_tdata <= read_data;
end
end
end else if (ethercat_working_counter_region[1]) begin
if (write_success | read_success) begin
if (ethercat_datagram_region_last[1]) begin
m_axis_tdata <= int_axis_tdata + {7'd0, calculate_carry};
end else begin
{calculate_carry, m_axis_tdata} <= {1'd0, int_axis_tdata} +
{(~read_write)? 9'd1:
(write_success & read_success)? 9'd3:
(write_success)? 9'd2: 9'd1};
end
end
end
end
end
end
end
// Register control logics
logic write_en, read_en;
logic [7:0] read_data;
logic [15:0] configured_station_address;
logic [15:0] configured_station_alias;
logic [31:0] esc_dl_control;
logic [7:0] al_status;
logic [7:0] eeprom_configuration;
logic [7:0] eeprom_pdi_access_state;
logic [15:0] eeprom_control_status;
logic [127:0] fmmu[2];
logic [63:0] sync_manager[2];
wire [15:0] target_offset_address = ethercat_datagram_offset_address + {4'd0, ethercat_datagram_data_counter};
wire [31:0] target_logical_address = ethercat_datagram_logical_address + {20'd0, ethercat_datagram_data_counter};
always_ff @(posedge clk) begin
if (rst) begin
read_data <= 'd0;
configured_station_address <= 'd0;
configured_station_alias <= 'd0;
esc_dl_control <= 'd0;
al_status <= AL_STATUS_INIT;
eeprom_configuration <= 'd0;
eeprom_pdi_access_state <= 'd0;
eeprom_control_status <= 'd0;
eeprom_address <= 'd0;
fmmu[0] <= 'd0;
fmmu[1] <= 'd0;
sync_manager[0] <= 'd0;
sync_manager[1] <= 'd0;
end else begin
if (s_axis_tvalid & s_axis_tready & valid_address & ethercat_datagram_data_region[0]) begin
write_en <= 1'b0; read_en <= 1'b0; read_data <= 'd0;
if (logical_address) begin
if (fmmu_log_address_offset[0] < fmmu_log_length[0]) begin
write_en <= fmmu_write_en[0]; read_en <= fmmu_read_en[0];
case (fmmu_phys_address[0])
sync_manager_address[0]: begin
if (write_req & fmmu_write_en[0]) sync_manager_out[0][fmmu_log_address_offset[0]*8+:8] <= s_axis_tdata;
if (read_req & fmmu_read_en[0]) read_data <= sync_manager_in[0][fmmu_log_address_offset[0]*8+:8];
end
sync_manager_address[1]: begin
if (write_req & fmmu_write_en[0]) sync_manager_out[1][fmmu_log_address_offset[0]*8+:8] <= s_axis_tdata;
if (read_req & fmmu_read_en[0]) read_data <= sync_manager_in[1][fmmu_log_address_offset[0]*8+:8];
end
default: ;
endcase
end else if (fmmu_log_address_offset[1] < fmmu_log_length[1]) begin
write_en <= fmmu_write_en[1]; read_en <= fmmu_read_en[1];
case (fmmu_phys_address[1])
sync_manager_address[0]: begin
if (write_req & fmmu_write_en[1]) sync_manager_out[0][fmmu_log_address_offset[1]*8+:8] <= s_axis_tdata;
if (read_req & fmmu_read_en[1]) read_data <= sync_manager_in[0][fmmu_log_address_offset[1]*8+:8];
end
sync_manager_address[1]: begin
if (write_req & fmmu_write_en[1]) sync_manager_out[1][fmmu_log_address_offset[1]*8+:8] <= s_axis_tdata;
if (read_req & fmmu_read_en[1]) read_data <= sync_manager_in[1][fmmu_log_address_offset[1]*8+:8];
end
default: ;
endcase
end
end else begin
write_en <= 1'b1; read_en <= 1'b1;
if (target_offset_address[15:1] == ADDR_ESC_INFORMATION[15:1]) begin
write_en <= 1'b0;
if (read_req) read_data <= 8'h00;
end else if (target_offset_address[15:1] == ADDR_CONFIGURED_STATION_ADDRESS[15:1]) begin
if (write_req) configured_station_address[target_offset_address[0]*8+:8] <= s_axis_tdata;
if (read_req) read_data <= configured_station_address[target_offset_address[0]*8+:8];
end else if (target_offset_address[15:1] == ADDR_CONFIGURED_STATION_ALIAS[15:1]) begin
if (write_req) configured_station_alias[target_offset_address[0]*8+:8] <= s_axis_tdata;
if (read_req) read_data <= configured_station_alias[target_offset_address[0]*8+:8];
end else if (target_offset_address[15:2] == ADDR_ESC_DL_CONTROL[15:2]) begin
if (write_req) esc_dl_control[target_offset_address[1:0]*8+:8] <= s_axis_tdata;
if (read_req) read_data <= esc_dl_control[target_offset_address[1:0]*8+:8];
end else if (target_offset_address[15:0] == ADDR_AL_CONTROL[15:0]) begin
if (write_req) al_status <= s_axis_tdata;
if (read_req) read_data <= al_status;
end else if (target_offset_address[15:0] == ADDR_AL_STATUS[15:0]) begin
write_en <= 1'b0;
if (read_req) read_data <= al_status;
end else if (target_offset_address[15:0] == ADDR_EEPROM_CONFIGURATION[15:0]) begin
if (write_req) eeprom_configuration <= s_axis_tdata;
if (read_req) read_data <= eeprom_configuration;
end else if (target_offset_address[15:0] == ADDR_EEPROM_PDI_ACCESS_STATE[15:0]) begin
if (write_req) eeprom_pdi_access_state <= s_axis_tdata;
if (read_req) read_data <= eeprom_pdi_access_state;
end else if (target_offset_address[15:1] == ADDR_EEPROM_CONTROL_STATUS[15:1]) begin
if (write_req) eeprom_control_status[target_offset_address[0]*8+:8] <= s_axis_tdata;
if (read_req) read_data <= eeprom_control_status[target_offset_address[0]*8+:8];
end else if (target_offset_address[15:2] == ADDR_EEPROM_ADDRESS[15:2]) begin
if (write_req) eeprom_address[target_offset_address[1:0]*8+:8] <= s_axis_tdata;
if (read_req) read_data <= eeprom_address[target_offset_address[1:0]*8+:8];
end else if (target_offset_address[15:2] == ADDR_EEPROM_DATA[15:2]) begin
write_en <= 1'b0;
if (read_req) read_data <= eeprom_data[target_offset_address[1:0]*8+:8];
end else if (target_offset_address[15:4] == ADDR_FMMU_0[15:4]) begin
if (write_req) fmmu[0][target_offset_address[3:0]*8+:8] <= s_axis_tdata;
if (read_req) read_data <= fmmu[0][target_offset_address[3:0]*8+:8];
end else if (target_offset_address[15:4] == ADDR_FMMU_1[15:4]) begin
if (write_req) fmmu[1][target_offset_address[3:0]*8+:8] <= s_axis_tdata;
if (read_req) read_data <= fmmu[1][target_offset_address[3:0]*8+:8];
end else if (target_offset_address[15:3] == ADDR_SYNC_MANAGER_0[15:3]) begin
if (write_req) sync_manager[0][target_offset_address[2:0]*8+:8] <= s_axis_tdata;
if (read_req) read_data <= sync_manager[0][target_offset_address[2:0]*8+:8];
end else if (target_offset_address[15:3] == ADDR_SYNC_MANAGER_1[15:3]) begin
if (write_req) sync_manager[1][target_offset_address[2:0]*8+:8] <= s_axis_tdata;
if (read_req) read_data <= sync_manager[1][target_offset_address[2:0]*8+:8];
end else begin
write_en <= 1'b0; read_en <= 1'b0; read_data <= 'd0;
end
end
end
end
end
// Write/Read success flags
logic write_success, read_success;
always_ff @(posedge clk) begin
if (ethercat_datagram_slave_address_region_lower) begin
write_success <= 1'b0;
read_success <= 1'b0;
end else if (ethercat_datagram_data_region[1]) begin
write_success <= (write_success | write_en) & write_req;
read_success <= (read_success | read_en) & read_req;
end
end
// Count the Ethernet packet
localparam ETHERNET_HEADER_LENGTH = 14;
localparam ETHERCAT_HEADER_LENGTH = 2;
logic [4:0] ethernet_counter;
always_ff @(posedge clk) begin
if (rst) begin
ethernet_counter <= 'd0;
end else begin
if (s_axis_tvalid & s_axis_tready) begin
if (s_axis_tlast) begin
ethernet_counter <= 'd0;
end else if (ethernet_counter < '1) begin
ethernet_counter <= ethernet_counter + 'd1;
end
end
end
end
// Count the EtherCAT datagram
localparam ETHERCAT_DATAGRAM_HEADER_LENGTH = 10;
localparam ETHERCAT_DATAGRAM_WORKING_COUNTER_LENGTH = 2;
logic [11:0] ethercat_datagram_counter[2];
always_ff @(posedge clk) begin
if (rst) begin
ethercat_datagram_counter[0] <= 'd0;
ethercat_datagram_counter[1] <= 'd0;
end else begin
if (s_axis_tvalid & s_axis_tready) begin
if (ethercat_datagram_region[0]) begin
if (ethercat_datagram_region_last[0]) begin
ethercat_datagram_counter[0] <= 'd0;
end else if (ethercat_datagram_counter[0] < '1) begin
ethercat_datagram_counter[0] <= ethercat_datagram_counter[0] + 'd1;
end
end
if (ethercat_datagram_region[1]) begin
if (ethercat_datagram_region_last[1]) begin
ethercat_datagram_counter[1] <= 'd0;
end else if (ethercat_datagram_counter[1] < '1) begin
ethercat_datagram_counter[1] <= ethercat_datagram_counter[1] + 'd1;
end
end
end
end
end
// Detect the EtherCAT datagram region
logic ethercat_datagram_region[2];
always_ff @(posedge clk) begin
if (rst) begin
ethercat_datagram_region[0] <= 1'b0;
end else begin
if (s_axis_tvalid & s_axis_tready) begin
if (ethercat_header_region_last) begin
ethercat_datagram_region[0] <= 1'b1;
end else if (~ethercat_datagram_next & ethercat_datagram_region_last[0]) begin
ethercat_datagram_region[0] <= 1'b0;
end
ethercat_datagram_region[1] <= ethercat_datagram_region[0];
end
end
end
// Utility logics and wires
logic [31:0] fmmu_log_address[2];
assign fmmu_log_address[0] = fmmu[0][31:0];
assign fmmu_log_address[1] = fmmu[1][31:0];
logic [31:0] fmmu_log_address_offset[2];
assign fmmu_log_address_offset[0] = target_logical_address - fmmu_log_address[0];
assign fmmu_log_address_offset[1] = target_logical_address - fmmu_log_address[1];
logic [15:0] fmmu_log_length[2];
assign fmmu_log_length[0] = fmmu[0][47:32];
assign fmmu_log_length[1] = fmmu[1][47:32];
logic fmmu_write_en[2];
assign fmmu_write_en[0] = fmmu[0][89];
assign fmmu_write_en[1] = fmmu[1][89];
logic fmmu_read_en[2];
assign fmmu_read_en[0] = fmmu[0][88];
assign fmmu_read_en[1] = fmmu[1][88];
logic [15:0] fmmu_phys_address[2];
assign fmmu_phys_address[0] = fmmu[0][79:64];
assign fmmu_phys_address[1] = fmmu[1][79:64];
logic [15:0] sync_manager_address[2];
assign sync_manager_address[0] = sync_manager[0][15:0];
assign sync_manager_address[1] = sync_manager[1][15:0];
wire ethernet_header_region = (ethernet_counter < ETHERNET_HEADER_LENGTH);
wire ethernet_frame_region = ~ethernet_header_region;
wire ethercat_header_region = ethernet_frame_region &
(ethernet_counter < (ETHERNET_HEADER_LENGTH +
ETHERCAT_HEADER_LENGTH));
wire ethercat_header_region_last = ethernet_frame_region &
(ethernet_counter == (ETHERNET_HEADER_LENGTH +
ETHERCAT_HEADER_LENGTH - 1));
wire [11:0] ethercat_datagram_data_counter = ethercat_datagram_counter[0] - ETHERCAT_DATAGRAM_HEADER_LENGTH;
wire ethercat_datagram_slave_address_region_lower = (ethercat_datagram_counter[0] == 'd2);
wire ethercat_datagram_slave_address_region_upper = (ethercat_datagram_counter[0] == 'd3);
logic ethercat_datagram_data_region[2];
assign ethercat_datagram_data_region[0] = (ethercat_datagram_counter[0] >= (ETHERCAT_DATAGRAM_HEADER_LENGTH)) &
(ethercat_datagram_counter[0] < (ETHERCAT_DATAGRAM_HEADER_LENGTH +
ethercat_datagram_length));
assign ethercat_datagram_data_region[1] = (ethercat_datagram_counter[1] >= (ETHERCAT_DATAGRAM_HEADER_LENGTH)) &
(ethercat_datagram_counter[1] < (ETHERCAT_DATAGRAM_HEADER_LENGTH +
ethercat_datagram_length));
logic ethercat_datagram_region_last[2];
assign ethercat_datagram_region_last[0] = (ethercat_datagram_counter[0] == (ETHERCAT_DATAGRAM_HEADER_LENGTH +
ethercat_datagram_length +
ETHERCAT_DATAGRAM_WORKING_COUNTER_LENGTH - 1));
assign ethercat_datagram_region_last[1] = (ethercat_datagram_counter[1] == (ETHERCAT_DATAGRAM_HEADER_LENGTH +
ethercat_datagram_length +
ETHERCAT_DATAGRAM_WORKING_COUNTER_LENGTH - 1));
logic ethercat_working_counter_region[2];
assign ethercat_working_counter_region[0] = (ethercat_datagram_counter[0] >= (ETHERCAT_DATAGRAM_HEADER_LENGTH +
ethercat_datagram_length)) &
(ethercat_datagram_counter[0] < (ETHERCAT_DATAGRAM_HEADER_LENGTH +
ethercat_datagram_length +
ETHERCAT_DATAGRAM_WORKING_COUNTER_LENGTH));
assign ethercat_working_counter_region[1] = (ethercat_datagram_counter[1] >= (ETHERCAT_DATAGRAM_HEADER_LENGTH +
ethercat_datagram_length)) &
(ethercat_datagram_counter[1] < (ETHERCAT_DATAGRAM_HEADER_LENGTH +
ethercat_datagram_length +
ETHERCAT_DATAGRAM_WORKING_COUNTER_LENGTH));
endmodule
`default_nettype wire