Commit e0e3a728 authored by Wesley W. Terpstra's avatar Wesley W. Terpstra

Merge branch 'dev-eca-software-queue-control' into HEAD

Tested with modelsim and quartus.
parents 5c33a4d4 a369cba9
......@@ -2,7 +2,7 @@ PREFIX ?= /usr/local
STAGING ?=
EB ?= no
ifeq ($(EB),no))
ifeq ($(EB),no)
EB_LIB ?= -letherbone
EB_INC ?=
else
......@@ -33,7 +33,7 @@ eca-ctl: eca-ctl.o libeca.a
eca-table: eca-table.o libeca.a
$(CXX) $(CXXFLAGS) -o $@ $^ -Wl,-rpath,$(PREFIX)/lib $(EB_LIB)
libeca.a: lib/hw-eca.o lib/hw-stream.o lib/hw-channel.o \
libeca.a: lib/hw-eca.o lib/hw-stream.o lib/hw-channel.o lib/hw-queue.o \
lib/load-table.o lib/store-table.o \
lib/table.o lib/probe-eca.o
rm -f $@
......
This diff is collapsed.
......@@ -28,6 +28,7 @@
#include <etherbone.h>
#include <string>
#include <vector>
#include <list>
namespace GSI_ECA {
......@@ -52,6 +53,12 @@ struct EventEntry {
: event(e), param(p), tef(t), time(i) { }
};
enum ActionStatus {
VALID = 0,
CONFLICT,
LATE
};
/* An action queued to be executed has these fields */
struct ActionEntry {
Event event;
......@@ -59,9 +66,10 @@ struct ActionEntry {
Tag tag;
Tef tef;
Time time;
ActionStatus status;
ActionEntry(Event e = 0, Param p = 0, Tag a = 0, Tef t = 0, Time i = 0)
: event(e), param(p), tag(a), tef(t), time(i) { }
ActionEntry(Event e = 0, Param p = 0, Tag a = 0, Tef t = 0, Time i = 0, ActionStatus s = VALID)
: event(e), param(p), tag(a), tef(t), time(i), status(s) { }
};
/* Software condition table entry fields */
......@@ -100,6 +108,52 @@ class Table {
friend struct ECA;
};
/* ======================================================================= */
/* Software interface to hardware action queues */
/* ======================================================================= */
struct ActionQueue {
/* ------------------------------------------------------------------- */
/* Constant hardware values */
/* ------------------------------------------------------------------- */
uint8_t sdb_ver_major;
uint8_t sdb_ver_minor;
uint32_t sdb_version;
uint32_t sdb_date;
std::string sdb_name;
uint16_t queue_size;
/* ------------------------------------------------------------------- */
/* Mutable hardware registers; only modify using methods below */
/* ------------------------------------------------------------------- */
bool arrival_enable; /* Enable arrival interrupt delivery */
uint32_t arrival_dest; /* Destination for arrival interrupt */
bool overflow_enable; /* Enable overflow interrupt delivery */
uint32_t overflow_dest; /* Destination for overflow interrupt */
uint32_t queued_actions; /* # of actions queued to be read */
uint32_t dropped_actions; /* # of actions dropped due to overflow */
/* ------------------------------------------------------------------- */
/* Access/modify the underlying hardware */
/* ------------------------------------------------------------------- */
Device device; /* Device which hosts this ECA */
eb_address_t address; /* Wishbone base address */
/* Reload mutable registers from hardware */
status_t refresh();
/* Clear all dropped counter */
status_t reset();
/* Hook/unhook interrupt handling */
status_t hook_arrival (bool enable, uint32_t dest);
status_t hook_overflow(bool enable, uint32_t dest);
/* Pop the next queued action from the queue */
status_t pop(ActionEntry& queue);
};
/* ======================================================================= */
/* Software interface to hardware action channels */
/* ======================================================================= */
......@@ -110,6 +164,8 @@ struct ActionChannel {
std::string name; /* Channel instance name */
unsigned queue_size; /* Size of the inspectable queue */
std::list<ActionQueue> queue; /* Only present if an AQ is connected */
/* ------------------------------------------------------------------- */
/* Mutable hardware registers; only modify using methods below */
/* ------------------------------------------------------------------- */
......
......@@ -851,6 +851,7 @@ begin
channels : for channel_idx in 0 to g_num_channels-1 generate
channel : eca_channel
generic map(
g_channel_idx => channel_idx,
g_log_table_size => g_log_queue_len,
g_log_latency => g_log_queue_len,
g_log_queue_depth => g_log_queue_len+1)
......@@ -859,6 +860,7 @@ begin
rst_n_i => a_rst_n_i,
drain_i => ra0_cq_drain (channel_idx),
freeze_i => ra0_cq_freeze(channel_idx),
eca_idx_i => rc_ce_idx, -- crosses clock domains, but held stable
addr_i => rc_cq_index, -- crosses clock domains, but held stable
fill_o => sa_qc_fill (channel_idx),
full_o => sa_qw_full (channel_idx),
......
......@@ -65,6 +65,7 @@ use work.eca_pkg.all;
entity eca_channel is
generic(
g_channel_idx : natural;
g_log_table_size : natural := 8;
g_log_latency : natural := 8; -- Must be <= g_log_table_size
g_log_queue_depth : natural := 9); -- Must be > g_log_latency
......@@ -73,6 +74,7 @@ entity eca_channel is
rst_n_i : in std_logic;
freeze_i : in std_logic; -- stop action outflow and use addr_i=>inspect_o
drain_i : in std_logic; -- stop action in+outflow and erase tables
eca_idx_i : in std_logic_vector(7 downto 0);
addr_i : in std_logic_vector(g_log_table_size-1 downto 0);
fill_o : out std_logic_vector(g_log_table_size downto 0);
full_o : out std_logic;
......@@ -402,6 +404,8 @@ begin
channel_o.tag <= td_dispatch_tag;
channel_o.tef <= td_dispatch_tef;
channel_o.time <= td_dispatch_time;
channel_o.eca_idx <= eca_idx_i;
channel_o.chl_idx <= std_logic_vector(to_unsigned(g_channel_idx, 8));
inspect_o.valid <= td_dispatch_valid;
inspect_o.conflict <= '0';
......@@ -411,6 +415,8 @@ begin
inspect_o.tag <= td_dispatch_tag;
inspect_o.tef <= td_dispatch_tef;
inspect_o.time <= td_dispatch_time;
inspect_o.eca_idx <= eca_idx_i;
inspect_o.chl_idx <= std_logic_vector(to_unsigned(g_channel_idx, 8));
dispatch_manage_kill <= dispatch_valid1;
dispatch_manage_index <= dispatch_index1;
......
......@@ -64,7 +64,7 @@ package eca_pkg is
constant c_eca_queue_sdb : t_sdb_device := (
abi_class => x"0000", -- undocumented device
abi_ver_major => x"01",
abi_ver_major => x"02",
abi_ver_minor => x"00",
wbd_endian => c_sdb_endian_big,
wbd_width => x"7", -- 8/16/32-bit port granularity
......@@ -75,7 +75,7 @@ package eca_pkg is
vendor_id => x"0000000000000651",
device_id => x"9bfa4560",
version => x"00000001",
date => x"20131107",
date => x"20140508",
name => "ECA_UNIT:ACTION_QUE")));
constant c_event_bits : natural := 64;
......@@ -100,6 +100,8 @@ package eca_pkg is
tag : t_tag;
tef : t_tef;
time : t_time;
eca_idx : std_logic_vector(7 downto 0);
chl_idx : std_logic_vector(7 downto 0);
end record t_channel;
type t_name is array(63 downto 0) of t_ascii;
......@@ -419,6 +421,7 @@ package eca_pkg is
component eca_channel is
generic(
g_channel_idx : natural;
g_log_table_size : natural := 8;
g_log_latency : natural := 8; -- Must be <= g_log_table_size
g_log_queue_depth : natural := 9); -- Must be > g_log_latency
......@@ -427,6 +430,7 @@ package eca_pkg is
rst_n_i : in std_logic;
freeze_i : in std_logic; -- stop action outflow and use addr_i=>inspect_o
drain_i : in std_logic; -- stop action in+outflow and erase tables
eca_idx_i : in std_logic_vector(7 downto 0);
addr_i : in std_logic_vector(g_log_table_size-1 downto 0);
fill_o : out std_logic_vector(g_log_table_size downto 0);
full_o : out std_logic;
......
--! @file eca_gpio_channel.vhd
--! @brief ECA-GPIO Adapter
--! @file eca_queue channel.vhd
--! @brief ECA-Queue Adapter
--! @author Wesley W. Terpstra <w.terpstra@gsi.de>
--!
--! Copyright (C) 2013 GSI Helmholtz Centre for Heavy Ion Research GmbH
......@@ -17,7 +17,9 @@
--! 0x0C RW : Queue overflow interrupt address (i_master_o.adr=reg, i_master_o.dat=[0=dropped])
--! 0x10 R : Queued actions
--! 0x14 RW : Dropped actions
--! 0x18 -- reserved --
--! 0x18 R : Meta-data
--! 0x0 R : eca index
--! 0x1 R : channel index
--! 0x1C R : flags (0x1=late, 0x2=conflict)
--! 0x20 R : Event1
--! 0x24 R : Event0
......@@ -412,7 +414,8 @@ begin
when 3 => q_slave_o.dat(rq_int_dropped'range) <= rq_int_dropped;
when 4 => q_slave_o.dat(rq_queued'range) <= std_logic_vector(rq_queued);
when 5 => q_slave_o.dat(rq_dropped'range) <= std_logic_vector(rq_dropped);
when 6 => null; -- reserved
when 6 => q_slave_o.dat(31 downto 24) <= a_channel_i.eca_idx;
q_slave_o.dat(23 downto 16) <= a_channel_i.chl_idx;
when 7 => q_slave_o.dat(0) <= sq_late;
q_slave_o.dat(1) <= sq_conflict;
-- Protect clock crossing (rq_widx updates well after memory written)
......
......@@ -384,6 +384,8 @@ begin
q_channel_o(i).tag <= r1_a_tag;
q_channel_o(i).tef <= r1_a_tef;
q_channel_o(i).time <= s1_a_action_time;
q_channel_o(i).eca_idx <= (others => '0'); -- meta-data added by channel
q_channel_o(i).chl_idx <= (others => '0');
end generate;
end rtl;
......@@ -47,20 +47,20 @@ status_t ActionChannel::refresh() {
if ((status = cycle.open(device)) != EB_OK)
return status;
cycle.write(address + ECAQ_SELECT, EB_DATA32, index << 16);
cycle.read(address + ECAQ_CTL, EB_DATA32, &ctl);
cycle.read(address + ECAQ_INT_DEST, EB_DATA32, &d_dest);
cycle.read(address + ECAQ_FILL, EB_DATA32, &d_fill);
cycle.read(address + ECAQ_VALID, EB_DATA32, &d_valid);
cycle.read(address + ECAQ_CONFLICT, EB_DATA32, &d_conflict);
cycle.read(address + ECAQ_LATE, EB_DATA32, &d_late);
cycle.write(address + ECAC_SELECT, EB_DATA32, index << 16);
cycle.read(address + ECAC_CTL, EB_DATA32, &ctl);
cycle.read(address + ECAC_INT_DEST, EB_DATA32, &d_dest);
cycle.read(address + ECAC_FILL, EB_DATA32, &d_fill);
cycle.read(address + ECAC_VALID, EB_DATA32, &d_valid);
cycle.read(address + ECAC_CONFLICT, EB_DATA32, &d_conflict);
cycle.read(address + ECAC_LATE, EB_DATA32, &d_late);
if ((status = cycle.close()) != EB_OK)
return status;
draining = (ctl & ECAQ_CTL_DRAIN) != 0;
frozen = (ctl & ECAQ_CTL_FREEZE) != 0;
int_enable = (ctl & ECAQ_CTL_INT_MASK) != 0;
draining = (ctl & ECAC_CTL_DRAIN) != 0;
frozen = (ctl & ECAC_CTL_FREEZE) != 0;
int_enable = (ctl & ECAC_CTL_INT_MASK) != 0;
int_dest = d_dest;
fill = (d_fill >> 16) & 0xFFFF;
max_fill = (d_fill >> 0) & 0xFFFF;
......@@ -78,11 +78,11 @@ status_t ActionChannel::reset() {
if ((status = cycle.open(device)) != EB_OK)
return status;
cycle.write(address + ECAQ_SELECT, EB_DATA32|EB_BIG_ENDIAN, index << 16);
cycle.write(address + ECAQ_FILL, EB_DATA32|EB_BIG_ENDIAN, 0);
cycle.write(address + ECAQ_VALID, EB_DATA32|EB_BIG_ENDIAN, 0);
cycle.write(address + ECAQ_CONFLICT, EB_DATA32|EB_BIG_ENDIAN, 0);
cycle.write(address + ECAQ_LATE, EB_DATA32|EB_BIG_ENDIAN, 0);
cycle.write(address + ECAC_SELECT, EB_DATA32|EB_BIG_ENDIAN, index << 16);
cycle.write(address + ECAC_FILL, EB_DATA32|EB_BIG_ENDIAN, 0);
cycle.write(address + ECAC_VALID, EB_DATA32|EB_BIG_ENDIAN, 0);
cycle.write(address + ECAC_CONFLICT, EB_DATA32|EB_BIG_ENDIAN, 0);
cycle.write(address + ECAC_LATE, EB_DATA32|EB_BIG_ENDIAN, 0);
if ((status = cycle.close()) != EB_OK)
return status;
......@@ -102,9 +102,9 @@ status_t ActionChannel::freeze(bool freeze) {
if ((status = cycle.open(device)) != EB_OK)
return status;
ctl = freeze?(ECAQ_CTL_FREEZE):(ECAQ_CTL_FREEZE<<8);
cycle.write(address + ECAQ_SELECT, EB_DATA32|EB_BIG_ENDIAN, index << 16);
cycle.write(address + ECAQ_CTL, EB_DATA32|EB_BIG_ENDIAN, ctl);
ctl = freeze?(ECAC_CTL_FREEZE):(ECAC_CTL_FREEZE<<8);
cycle.write(address + ECAC_SELECT, EB_DATA32|EB_BIG_ENDIAN, index << 16);
cycle.write(address + ECAC_CTL, EB_DATA32|EB_BIG_ENDIAN, ctl);
if ((status = cycle.close()) != EB_OK)
return status;
......@@ -121,9 +121,9 @@ status_t ActionChannel::drain(bool drain) {
if ((status = cycle.open(device)) != EB_OK)
return status;
ctl = drain?(ECAQ_CTL_DRAIN):(ECAQ_CTL_DRAIN<<8);
cycle.write(address + ECAQ_SELECT, EB_DATA32|EB_BIG_ENDIAN, index << 16);
cycle.write(address + ECAQ_CTL, EB_DATA32|EB_BIG_ENDIAN, ctl);
ctl = drain?(ECAC_CTL_DRAIN):(ECAC_CTL_DRAIN<<8);
cycle.write(address + ECAC_SELECT, EB_DATA32|EB_BIG_ENDIAN, index << 16);
cycle.write(address + ECAC_CTL, EB_DATA32|EB_BIG_ENDIAN, ctl);
if ((status = cycle.close()) != EB_OK)
return status;
......@@ -140,11 +140,11 @@ status_t ActionChannel::hook(bool enable, uint32_t dest) {
return status;
/* Clear the interrupt, set the address, possibly re-enable interrupt */
cycle.write(address + ECAQ_SELECT, EB_DATA32|EB_BIG_ENDIAN, index << 16);
cycle.write(address + ECAQ_CTL, EB_DATA32|EB_BIG_ENDIAN, ECAQ_CTL_INT_MASK<<8);
cycle.write(address + ECAQ_INT_DEST, EB_DATA32|EB_BIG_ENDIAN, dest);
cycle.write(address + ECAC_SELECT, EB_DATA32|EB_BIG_ENDIAN, index << 16);
cycle.write(address + ECAC_CTL, EB_DATA32|EB_BIG_ENDIAN, ECAC_CTL_INT_MASK<<8);
cycle.write(address + ECAC_INT_DEST, EB_DATA32|EB_BIG_ENDIAN, dest);
if (enable) {
cycle.write(address + ECAQ_CTL, EB_DATA32|EB_BIG_ENDIAN, ECAQ_CTL_INT_MASK);
cycle.write(address + ECAC_CTL, EB_DATA32|EB_BIG_ENDIAN, ECAC_CTL_INT_MASK);
}
if ((status = cycle.close()) != EB_OK)
......@@ -178,23 +178,23 @@ status_t ActionChannel::load(std::vector<ActionEntry>& table) {
if ((status = cycle.open(device)) != EB_OK)
return status;
cycle.write(address + ECAQ_SELECT, EB_DATA32|EB_BIG_ENDIAN, (index << 16) | i);
cycle.read (address + ECAQ_CTL, EB_DATA32, &ctl);
cycle.write(address + ECAC_SELECT, EB_DATA32|EB_BIG_ENDIAN, (index << 16) | i);
cycle.read (address + ECAC_CTL, EB_DATA32, &ctl);
cycle.read (address + ECAQ_EVENT1, EB_DATA32, &event1);
cycle.read (address + ECAQ_EVENT0, EB_DATA32, &event0);
cycle.read (address + ECAQ_PARAM1, EB_DATA32, &param1);
cycle.read (address + ECAQ_PARAM0, EB_DATA32, &param0);
cycle.read (address + ECAQ_TAG, EB_DATA32, &tag);
cycle.read (address + ECAQ_TEF, EB_DATA32, &tef);
cycle.read (address + ECAQ_TIME1, EB_DATA32, &time1);
cycle.read (address + ECAQ_TIME0, EB_DATA32, &time0);
cycle.read (address + ECAC_EVENT1, EB_DATA32, &event1);
cycle.read (address + ECAC_EVENT0, EB_DATA32, &event0);
cycle.read (address + ECAC_PARAM1, EB_DATA32, &param1);
cycle.read (address + ECAC_PARAM0, EB_DATA32, &param0);
cycle.read (address + ECAC_TAG, EB_DATA32, &tag);
cycle.read (address + ECAC_TEF, EB_DATA32, &tef);
cycle.read (address + ECAC_TIME1, EB_DATA32, &time1);
cycle.read (address + ECAC_TIME0, EB_DATA32, &time0);
if ((status = cycle.close()) != EB_OK)
return status;
/* Is the record invalid? */
if (((ctl >> 24) & ECAQ_STATUS_VALID) == 0) continue;
if (((ctl >> 24) & ECAC_STATUS_VALID) == 0) continue;
ActionEntry ae;
......@@ -203,9 +203,7 @@ status_t ActionChannel::load(std::vector<ActionEntry>& table) {
ae.tag = tag;
ae.tef = tef;
ae.time = time1; ae.time <<= 32; ae.time += time0;
/* late events have negative timestamps */
if (((ctl >> 24) & ECAQ_STATUS_LATE) == 1) ae.time = -ae.time;
ae.status = (((ctl >> 24) & ECAC_STATUS_LATE) == 1)?LATE:VALID;
table.push_back(ae);
}
......
......@@ -31,6 +31,7 @@
#define GSI_VENDOR_ID 0x651
#define ECA_DEVICE_ID 0x8752bf44U
#define ECAE_DEVICE_ID 0x8752bf45U
#define ECAQ_DEVICE_ID 0x9bfa4560U
#define ECA_FEATURE_INSPECT_TABLE 0x1
#define ECA_FEATURE_INSPECT_QUEUE 0x2
......@@ -66,36 +67,54 @@
#define ECA_FREQ_2S 0x3D
#define ECA_FREQ_DIV 0x3E
#define ECAQ_STATUS_VALID 0x01
#define ECAQ_STATUS_LATE 0x02
#define ECAQ_CTL_DRAIN 0x01
#define ECAQ_CTL_FREEZE 0x02
#define ECAQ_CTL_INT_MASK 0x04
#define ECAQ_SELECT 0x40
#define ECAQ_CHANNEL 0x40
#define ECAQ_INDEX 0x42
#define ECAQ_CTL 0x44
#define ECAQ_STATUS 0x44
#define ECAQ_NAME 0x45
#define ECAQ_CTL_CLEAR 0x46
#define ECAQ_CTL_SET 0x47
#define ECAQ_INT_DEST 0x48
#define ECAQ_FILL 0x50
#define ECAQ_MAX_FILL 0x52
#define ECAQ_VALID 0x54
#define ECAQ_CONFLICT 0x58
#define ECAQ_LATE 0x5C
#define ECAQ_EVENT1 0x60
#define ECAQ_EVENT0 0x64
#define ECAQ_PARAM1 0x68
#define ECAQ_PARAM0 0x6C
#define ECAQ_TAG 0x70
#define ECAQ_TEF 0x74
#define ECAQ_TIME1 0x78
#define ECAQ_TIME0 0x7C
#define ECAC_STATUS_VALID 0x01
#define ECAC_STATUS_LATE 0x02
#define ECAC_CTL_DRAIN 0x01
#define ECAC_CTL_FREEZE 0x02
#define ECAC_CTL_INT_MASK 0x04
#define ECAC_SELECT 0x40
#define ECAC_CHANNEL 0x40
#define ECAC_INDEX 0x42
#define ECAC_CTL 0x44
#define ECAC_STATUS 0x44
#define ECAC_NAME 0x45
#define ECAC_CTL_CLEAR 0x46
#define ECAC_CTL_SET 0x47
#define ECAC_INT_DEST 0x48
#define ECAC_FILL 0x50
#define ECAC_MAX_FILL 0x52
#define ECAC_VALID 0x54
#define ECAC_CONFLICT 0x58
#define ECAC_LATE 0x5C
#define ECAC_EVENT1 0x60
#define ECAC_EVENT0 0x64
#define ECAC_PARAM1 0x68
#define ECAC_PARAM0 0x6C
#define ECAC_TAG 0x70
#define ECAC_TEF 0x74
#define ECAC_TIME1 0x78
#define ECAC_TIME0 0x7C
#define ECAQ_CTL 0x0
#define ECAQ_INT_MASK 0x4
#define ECAQ_ARRIVAL 0x8
#define ECAQ_OVERFLOW 0xC
#define ECAQ_QUEUED 0x10
#define ECAQ_DROPPED 0x14
#define ECAQ_META 0x18
#define ECAQ_FLAGS 0x1C
#define ECAQ_EVENT1 0x20
#define ECAQ_EVENT0 0x24
#define ECAQ_PARAM1 0x28
#define ECAQ_PARAM0 0x2C
#define ECAQ_TAG 0x30
#define ECAQ_TEF 0x34
#define ECAQ_TIME1 0x38
#define ECAQ_TIME0 0x3C
namespace GSI_ECA {
......
/** @file hw-queue.cpp
* @brief C++ Wrapper for the ECA Queue hardware.
* @author Wesley W. Terpstra <w.terpstra@gsi.de>
*
* Copyright (C) 2014 GSI Helmholtz Centre for Heavy Ion Research GmbH
*
* Read-write control of Queue registers.
*
*******************************************************************************
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*******************************************************************************
*/
#define __STDC_FORMAT_MACROS
#define __STDC_LIMIT_MACROS
#define __STDC_CONSTANT_MACROS
#include <stdio.h>
#include <assert.h>
#include "eca.h"
#include "hw-eca.h"
namespace GSI_ECA {
status_t ActionQueue::refresh() {
Cycle cycle;
eb_status_t status;
eb_data_t d_int_mask;
eb_data_t d_arrival_dest;
eb_data_t d_overflow_dest;
eb_data_t d_queued;
eb_data_t d_dropped;
if ((status = cycle.open(device)) != EB_OK)
return status;
cycle.read(address + ECAQ_INT_MASK, EB_DATA32, &d_int_mask);
cycle.read(address + ECAQ_ARRIVAL, EB_DATA32, &d_arrival_dest);
cycle.read(address + ECAQ_OVERFLOW, EB_DATA32, &d_overflow_dest);
cycle.read(address + ECAQ_QUEUED, EB_DATA32, &d_queued);
cycle.read(address + ECAQ_DROPPED, EB_DATA32, &d_dropped);
if ((status = cycle.close()) != EB_OK)
return status;
arrival_enable = (d_int_mask & 1) != 0;
overflow_enable = (d_int_mask & 2) != 0;
arrival_dest = d_arrival_dest & 0xFFFFFFFF;
overflow_dest = d_overflow_dest & 0xFFFFFFFF;
queued_actions = d_queued & 0xFFFFFFFF;
dropped_actions = d_dropped & 0xFFFFFFFF;
return EB_OK;
}
status_t ActionQueue::reset() {
Cycle cycle;
eb_status_t status;
if ((status = device.write(address + ECAQ_DROPPED, EB_DATA32|EB_BIG_ENDIAN, 0)) != EB_OK)
return status;
dropped_actions = 0;
return EB_OK;
}
status_t ActionQueue::hook_arrival(bool enable, uint32_t dest) {
Cycle cycle;
eb_status_t status;
if ((status = cycle.open(device)) != EB_OK)
return status;
/* Clear the interrupt, set the address, possibly re-enable interrupt */
cycle.write(address + ECAQ_INT_MASK, EB_DATA32|EB_BIG_ENDIAN, overflow_enable?2:0);
cycle.write(address + ECAQ_ARRIVAL, EB_DATA32|EB_BIG_ENDIAN, dest);
if (enable) {
cycle.write(address + ECAQ_INT_MASK, EB_DATA32|EB_BIG_ENDIAN, overflow_enable?3:1);
}
if ((status = cycle.close()) != EB_OK)
return status;
arrival_enable = enable;
arrival_dest = dest;
return EB_OK;
}
status_t ActionQueue::hook_overflow(bool enable, uint32_t dest) {
Cycle cycle;
eb_status_t status;
if ((status = cycle.open(device)) != EB_OK)
return status;
/* Clear the interrupt, set the address, possibly re-enable interrupt */
cycle.write(address + ECAQ_INT_MASK, EB_DATA32|EB_BIG_ENDIAN, arrival_enable?1:0);
cycle.write(address + ECAQ_OVERFLOW, EB_DATA32|EB_BIG_ENDIAN, dest);
if (enable) {
cycle.write(address + ECAQ_INT_MASK, EB_DATA32|EB_BIG_ENDIAN, arrival_enable?3:2);
}
if ((status = cycle.close()) != EB_OK)
return status;
overflow_enable = enable;
overflow_dest = dest;
return EB_OK;
}
status_t ActionQueue::pop(ActionEntry& queue) {
Cycle cycle;
eb_status_t status;
eb_data_t queued, flags;
eb_data_t event1, event0;
eb_data_t param1, param0;
eb_data_t tag, tef;
eb_data_t time1, time0;
if (queued_actions == 0) return EB_FAIL;
if ((status = cycle.open(device)) != EB_OK)
return status;
cycle.read (address + ECAQ_FLAGS, EB_DATA32, &flags);
cycle.read (address + ECAQ_EVENT1, EB_DATA32, &event1);
cycle.read (address + ECAQ_EVENT0, EB_DATA32, &event0);
cycle.read (address + ECAQ_PARAM1, EB_DATA32, &param1);
cycle.read (address + ECAQ_PARAM0, EB_DATA32, &param0);
cycle.read (address + ECAQ_TAG, EB_DATA32, &tag);
cycle.read (address + ECAQ_TEF, EB_DATA32, &tef);
cycle.read (address + ECAQ_TIME1, EB_DATA32, &time1);
cycle.read (address + ECAQ_TIME0, EB_DATA32, &time0);
cycle.write(address + ECAQ_CTL, EB_DATA32, 1); /* pop */
cycle.read (address + ECAQ_QUEUED, EB_DATA32, &queued);
if ((status = cycle.close()) != EB_OK)
return status;
queue.status =
(flags & 2) != 0 ? CONFLICT :
(flags & 1) != 0 ? LATE :
VALID;
queue.event = event1; queue.event <<= 32; queue.event += event0;
queue.param = param1; queue.param <<= 32; queue.param += param0;
queue.tag = tag;
queue.tef = tef;
queue.time = time1; queue.time <<= 32; queue.time += time0;
queued_actions = queued;
return EB_OK;
}
}
......@@ -39,6 +39,7 @@ struct SearchRecord {
eb_status_t status;
std::vector<ECA>* ecas;
std::vector<EventStream> streams;
std::vector<ActionQueue> queues;
};
static void trim(std::string& s) {
......@@ -63,6 +64,19 @@ void eca_sdb_search(SearchRecord* record, Device dev, const struct sdb_table* sd
case sdb_record_device: {
if (des->device.sdb_component.product.vendor_id == GSI_VENDOR_ID) {
switch (des->device.sdb_component.product.device_id) {
case ECAQ_DEVICE_ID: {
if (des->device.abi_ver_major != 2) break;
ActionQueue aq;
aq.address = des->device.sdb_component.addr_first;
aq.sdb_ver_major = des->device.abi_ver_major;
aq.sdb_ver_minor = des->device.abi_ver_minor;
aq.sdb_version = des->device.sdb_component.product.version;
aq.sdb_date = des->device.sdb_component.product.date;
aq.sdb_name = std::string((const char*)&des->device.sdb_component.product.name[0], 19);
trim(aq.sdb_name);
record->queues.push_back(aq);
break;
}
case ECAE_DEVICE_ID: {
if (des->device.abi_ver_major != 2) break;
EventStream es;
......@@ -209,23 +223,23 @@ status_t ECA::probe(Device device, std::vector<ECA>& ecas) {
if ((status = cycle.open(device)) != EB_OK)
return status;
cycle.write(eca.address + ECAQ_SELECT, EB_DATA32, c << 16);
cycle.write(eca.address + ECAC_SELECT, EB_DATA32, c << 16);
for (unsigned j = 0; j < 64; ++j)
cycle.read(eca.address + ECAQ_CTL, EB_DATA32, &name[j]);
cycle.read(eca.address + ECAQ_INT_DEST, EB_DATA32, &dest);
cycle.read(eca.address + ECAQ_FILL, EB_DATA32, &fill);
cycle.read(eca.address + ECAQ_VALID, EB_DATA32, &valid);
cycle.read(eca.address + ECAQ_CONFLICT, EB_DATA32, &conflict);
cycle.read(eca.address + ECAQ_LATE, EB_DATA32, &late);
cycle.read(eca.address + ECAC_CTL, EB_DATA32, &name[j]);
cycle.read(eca.address + ECAC_INT_DEST, EB_DATA32, &dest);
cycle.read(eca.address + ECAC_FILL, EB_DATA32, &fill);
cycle.read(eca.address + ECAC_VALID, EB_DATA32, &valid);
cycle.read(eca.address + ECAC_CONFLICT, EB_DATA32, &conflict);
cycle.read(eca.address + ECAC_LATE, EB_DATA32, &late);
if ((status = cycle.close()) != EB_OK)
return status;
ac.name = eca_extract_name(name);
ac.queue_size = eca.inspect_queue?eca.queue_size:0;
ac.draining = (name[0] & ECAQ_CTL_DRAIN) != 0;
ac.frozen = (name[0] & ECAQ_CTL_FREEZE) != 0;
ac.int_enable = (name[0] & ECAQ_CTL_INT_MASK) != 0;
ac.draining = (name[0] & ECAC_CTL_DRAIN) != 0;
ac.frozen = (name[0] & ECAC_CTL_FREEZE) != 0;
ac.int_enable = (name[0] & ECAC_CTL_INT_MASK) != 0;
ac.int_dest = dest;
ac.fill = (fill >> 16) & 0xFFFF;
ac.max_fill = (fill >> 0) & 0xFFFF;
......@@ -238,9 +252,6 @@ status_t ECA::probe(Device device, std::vector<ECA>& ecas) {
}
/* Phase 3 -- Deduce stream relationships */
std::vector<uint8_t> ids;
ids.resize(record.streams.size());
for (unsigned s = 0; s < record.streams.size(); ++s) {
EventStream& es = record.streams[s];
......@@ -248,12 +259,7 @@ status_t ECA::probe(Device device, std::vector<ECA>& ecas) {
status = device.read(es.address, EB_DATA32, &id);
if (status != EB_OK) return status;
ids[s] = id;
}
for (unsigned s = 0; s < record.streams.size(); ++s) {
EventStream& es = record.streams[s];
uint8_t mid = ids[s];
uint8_t mid = id;
if (mid >= ecas.size()) {
/* fprintf(stderr, "Unmatched ECA Event stream; id: %d\n", mid); */
continue;
......@@ -262,6 +268,52 @@ status_t ECA::probe(Device device, std::vector<ECA>& ecas) {
ecas[mid].streams.push_back(es);
}
/* Phase 4 -- Deduce queue relationships */
for (unsigned q = 0; q < record.queues.size(); ++q) {
eb_data_t ctl, mask;
eb_data_t arrival, overflow;
eb_data_t queued, dropped;
ActionQueue& aq = record.queues[q];
if ((status = cycle.open(device)) != EB_OK)
return status;
cycle.read(aq.address + ECAQ_CTL, EB_DATA32, &ctl);
cycle.read(aq.address + ECAQ_INT_MASK, EB_DATA32, &mask);
cycle.read(aq.address + ECAQ_ARRIVAL, EB_DATA32, &arrival);
cycle.read(aq.address + ECAQ_OVERFLOW, EB_DATA32, &overflow);
cycle.read(aq.address + ECAQ_QUEUED, EB_DATA32, &queued);
cycle.read(aq.address + ECAQ_DROPPED, EB_DATA32, &dropped);
cycle.read(aq.address + ECAQ_META, EB_DATA32, &id);
if ((status = cycle.close()) != EB_OK)
return status;
uint8_t mid = (id >> 24) & 0xFF;
uint8_t cid = (id >> 16) & 0xFF;
if (mid >= ecas.size() || cid >= ecas[mid].channels.size()) {
/* fprintf(stderr, "Unmatched ECA Queue; id: %d idx: %d\n", mid, idx); */
continue;
}
if (!ecas[mid].channels[cid].queue.empty()) {
/* fprintf(stderr, "Duplicate ECA Queue; id: %d idx: %d\n", mid, idx); */
continue;
}
aq.device = ecas[mid].device;
aq.queue_size = (ctl >> 16) & 0xFFFF;
aq.arrival_enable = (mask & 1) != 0;
aq.overflow_enable = (mask & 2) != 0;
aq.arrival_dest = arrival & 0xFFFFFFFF;
aq.overflow_dest = overflow & 0xFFFFFFFF;
aq.queued_actions = queued & 0xFFFFFFFF;
aq.dropped_actions = dropped & 0xFFFFFFFF;
ecas[mid].channels[cid].queue.push_back(aq);
}
return EB_OK;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment