How do I get a list of unconnected cell ports using the Yosys RTLIL API? - yosys

For a larger project, I need to create a list of unconnected cell ports using the Yosys RTLIL API. What is the best strategy for doing so?

The plain RTLIL API does not provide any indexes. You can determine the net connected to a port, but not the ports connected to a net. There are powerful indexers available in Yosys that can help you here, for example ModIndex from kernel/modtools.h, but in most cases it is simplest to create a custom index for whatever you need.
In this case we just need a dict<> that counts the number of cells connected to a net bit. We make two passes over all cell ports. In the first pass we count the number of connections for each signal bit, and in a second pass we determine if a cell port is the only port connected to that bit:
void find_unconn_cellports(Module *module)
{
SigMap sigmap(module);
dict<SigBit, int> sigbit_conncounts;
for (auto wire : module->wires()) {
if (wire->port_input)
for (auto bit : sigmap(wire))
sigbit_conncounts[bit]++;
if (wire->port_output)
for (auto bit : sigmap(wire))
sigbit_conncounts[bit]++;
}
for (auto cell : module->cells())
for (auto conn : cell->connections())
for (auto bit : conn.second)
sigbit_conncounts[sigmap(bit)]++;
for (auto cell : module->cells())
for (auto conn : cell->connections())
for (int i = 0; i < GetSize(conn.second); i++)
if (sigbit_conncounts.at(sigmap(conn.second[i])) == 1)
log("Unconnected cell port bit: %s.%s.%s[%d]\n",
log_id(module), log_id(cell), log_id(conn.first), i);
}
Using a similar approach we can find all undriven cell ports:
void find_undriven_cellports(Module *module)
{
SigMap sigmap(module);
pool<SigBit> driven_sigbit;
for (auto wire : module->wires()) {
if (wire->port_input)
for (auto bit : sigmap(wire))
driven_sigbit.insert(bit);
}
for (auto cell : module->cells())
for (auto conn : cell->connections())
if (cell->output(conn.first))
for (auto bit : sigmap(conn.second))
driven_sigbit.insert(bit);
for (auto cell : module->cells())
for (auto conn : cell->connections())
if (cell->input(conn.first))
for (int i = 0; i < GetSize(conn.second); i++) {
auto bit = sigmap(conn.second[i]);
if (bit.wire && !driven_sigbit.count(bit))
log("Undriven cell port bit: %s.%s.%s[%d]\n",
log_id(module), log_id(cell), log_id(conn.first), i);
}
}
Or all unused cell ports:
void find_unused_cellports(Module *module)
{
SigMap sigmap(module);
pool<SigBit> used_sigbit;
for (auto wire : module->wires()) {
if (wire->port_output)
for (auto bit : sigmap(wire))
used_sigbit.insert(bit);
}
for (auto cell : module->cells())
for (auto conn : cell->connections())
if (cell->input(conn.first))
for (auto bit : sigmap(conn.second))
used_sigbit.insert(bit);
for (auto cell : module->cells())
for (auto conn : cell->connections())
if (cell->output(conn.first))
for (int i = 0; i < GetSize(conn.second); i++)
if (used_sigbit.count(sigmap(conn.second[i])) == 0)
log("Unused cell port bit: %s.%s.%s[%d]\n",
log_id(module), log_id(cell), log_id(conn.first), i);
}

Related

Sequence that writes to either one of two different registers, but with the same fields

I'm working on an old environment, that is not UVM compatible, but uses the vr_ad_reg.
One of the issues with this old environment is that instead of instantiating a regfile twice for one of the modules (which in RTL is indeed instantiated twice), there is a double definition for the entire regfile and the registers in it.
For instance, I have two regfiles: "GAD" and "GAD_RX", and they both have a register defined like this:
reg_def GAD_SEQ GAD 20'h00010 {
reg_fld s_event : uint (bits : 7) : RW : 0x0;
reg_fld smpl_en : bit : RW : 0x0;
reg_fld int_en : bit : RW : 0x0;
reg_fld dma_req : bit : RW : 0x0;
reg_fld smpl_tag : uint (bits : 2) : RW : 0x0;
reg_fld ch_tag : uint (bits : 4) : RW : 0x0;
reg_fld smpl_point : uint (bits : 16) : RW : 0x0;
};
reg_def GAD_RX_SEQ GAD_RX 20'h00010 {
reg_fld s_event : uint (bits : 7) : RW : 0x0;
reg_fld smpl_en : bit : RW : 0x0;
reg_fld int_en : bit : RW : 0x0;
reg_fld dma_req : bit : RW : 0x0;
reg_fld smpl_tag : uint (bits : 2) : RW : 0x0;
reg_fld ch_tag : uint (bits : 4) : RW : 0x0;
reg_fld smpl_point : uint (bits : 16) : RW : 0x0;
};
As you can see, the regs are identical. I don't wish to replace the entire definition, because it is based on scripts that also generate RTL, and it's too much hassle and risk to try and rewrite them. But, I do want to be able to write a sequence that can write to both of them by constraining them to either one of the GADs.
I defined a struct member for all sequences that write to these registers:
type gad_type_t : [GAD,RX_GAD];
extend ocp_master_sequence_kind_t : [CONFIG_ADC_SEQ];
//This sequence writes a single line to GAD sequencer
extend CONFIG_ADC_SEQ ocp_master_sequence_q {
smpl_point : int(bits:16);
dma_req : bit;
int_en : bit;
smpl_en : bit;
ch_tag : uint(bits:4);
smpl_tag : uint(bits:2);
samp_sig : uint(bits:4);
keep soft samp_sig==0;
//which GAD to config
gad_type : gad_type_t;
keep soft gad_type==GAD;
I tried declaring register variable with macro but failed completely:
//Macro for declaring either GAD or RX_GAD register variable
define <get_gad_reg'action> "gad_reg <var_name'name> : <gad_type'exp> <reg_suffix'exp>" as computed {
var gad_regname : string;
var gad_type : gad_type_t = <gad_type'exp>;
var reg_suffix_s : string = <reg_suffix'exp>;
gad_regname = gad_type == RX_GAD ? append("GAD_RX_",reg_suffix_s) : append("GAD_",reg_suffix_s);
return append("var ",<var_name'name>," : ",gad_regname," vr_ad_reg = driver.get_reg_by_kind(",gad_regname,").as_a(",gad_regname," vr_ad_reg)");
};
Macro is supposed to be used in this way inside the body of the sequence:
gad_reg gad_seq_r : gad_type SEQ;
Which I hoped would translate to:
var gad_seq_r : GAD_SEQ vr_ad_reg = driver.get_reg_by_kind(GAD_SEQ).as_a(GAD_SEQ vr_ad_reg);
or:
var gad_seq_r : GAD_RX_SEQ vr_ad_reg = driver.get_reg_by_kind(GAD_RX_SEQ).as_a(GAD_RX_SEQ vr_ad_reg);
It worked for GAD, but not for RX_GAD, after much debugging I deduced that the gad_type isn't being matched right and the macro just takes the else clause on the conditional assignment.
I decided to try a different approach and not use macro, I tried doing this with the 'when' clause in the sequence itself:
when GAD {
body()#driver.clock is {
var gad_seq_r : GAD_SEQ vr_ad_reg = driver.get_reg_by_kind(GAD_SEQ).as_a(GAD_SEQ vr_ad_reg);
};
};
when RX_GAD {
body()#driver.clock is {
var gad_seq_r : GAD_RX_SEQ vr_ad_reg = driver.get_reg_by_kind(GAD_RX_SEQ).as_a(GAD_RX_SEQ vr_ad_reg);
};
};
body()#driver.clock is also {
gad_seq_r.smpl_point = last_line ? 0x8000 : smpl_point;
gad_seq_r.ch_tag = ch_tag;
gad_seq_r.smpl_tag = smpl_tag;
gad_seq_r.dma_req = dma_req;
gad_seq_r.int_en = int_en;
gad_seq_r.smpl_en = smpl_en;
gad_seq_r.s_event = s_event[6:0];
do WR_REG seq keeping {.reg==gad_seq_r;};
};
That doesn't compile, because the compiler doesn't recognize gad_seq_r outside of 'when' clause.
I don't know if there is a solution for this outside of duplicating code for GAD and RX_GAD, but I thought I might give it a shot here.
Either way, next project we will build a more reusable register database.
If you survived this far, thanks for your attention.
Since both of your registers have the exact same layout, you can just reference any one of the types inside your sequence, build up the desired value based on your sequence fields and then use write_reg <reg> value <val>:
extend CONFIG_ADC_SEQ ocp_master_sequence_q {
gad_type : gad_type_t;
smpl_point: int(bits:16);
// ... all other sequence fields that model register settings
// Used by 'write_reg'
!gad_reg: vr_ad_reg;
body() #driver.clock is also {
// Dummy register variable. Could be of either GAD_SEQ or GAD_RX_SEQ type
var dummy_gad_reg: GAD_SEQ vr_ad_reg;
dummy_gad_reg.smpl_point = smpl_point;
// ... set all other fields of 'gad_seq_r' based on your sequence fields
// Get a pointer to the "real" GAD reg you're trying to access
var real_gad_reg: vr_ad_reg;
if gad_type == GAD {
real_gad_reg = driver.get_reg_by_kind(GAD_SEQ);
}
else {
real_gad_reg = driver.get_reg_by_kind(GAD_RX_SEQ);
};
// Instruct 'vr_ad' to write the value in your dummy reg to the real reg
write_reg gad_reg { .static_item == real_gad_reg }
val dummy_gad_reg.get_cur_value();
};
};
I noticed you're using some WR_REG sequence to write your registers, which takes the register to be written as an argument. If using write_reg isn't an option (for whatever reason) and you have to use your sequence, I think you could replace the call to write_reg from above with:
real_gad_reg.write_reg_val(dummy_gad_reg.get_cur_value());
do WR_REG seq keeping {
.reg == real_gad_reg;
};

How to get selected adapter's MAC address in WinPcap?

For example, when program runs, I entered 1 as input and wanted to get MAC address of that interface in here. How can I do that?
I did a lot of work trying to figure out how to both get the mac address for an arbitrary interface under Windows, and matching that to the device info you get back from WinPCap.
A lot of posts say you should use GetAdaptersInfo or similar functions to get the mac address, but unfortunately, those functions only work with an interface that has ipv4 or ipv6 bound to it. I had a network card that purposely wasn't bound to anything, so that Windows wouldn't send any data over it.
GetIfTable(), however, seems to actually get you every interface on the system (there were 40 some odd on mine). It has the hardware mac address for each interface, so you just need to match it to the corresponding WinPCap device. The device name in WinPCap has a long GUID, which is also present in the name field of the interface table entries you get from GetIfTable. The names don't match exactly, though, so you have to extract the GUID from each name and match that. An additional complication is that the name field in the WinPCap device is a regular character string, but the name in the data you get from GetIfTable is a wide character string. The code below worked for me on two different systems, one Windows 7 and another Windows 10. I used the Microsoft GetIfTable example code as a starting point:
#include <winsock2.h>
#include <iphlpapi.h>
#include <stdio.h>
#include <stdlib.h>
#pragma comment(lib, "IPHLPAPI.lib")
#include <pcap.h>
// Compare the guid parts of both names and see if they match
int compare_guid(wchar_t *wszPcapName, wchar_t *wszIfName)
{
wchar_t *pc, *ic;
// Find first { char in device name from pcap
for (pc = wszPcapName; ; ++pc)
{
if (!*pc)
return -1;
if (*pc == L'{'){
pc++;
break;
}
}
// Find first { char in interface name from windows
for (ic = wszIfName; ; ++ic)
{
if (!*ic)
return 1;
if (*ic == L'{'){
ic++;
break;
}
}
// See if the rest of the GUID string matches
for (;; ++pc,++ic)
{
if (!pc)
return -1;
if (!ic)
return 1;
if ((*pc == L'}') && (*ic == L'}'))
return 0;
if (*pc != *ic)
return *ic - *pc;
}
}
// Find mac address using GetIFTable, since the GetAdaptersAddresses etc functions
// ony work with adapters that have an IP address
int get_mac_address(pcap_if_t *d, u_char mac_addr[6])
{
// Declare and initialize variables.
wchar_t* wszWideName = NULL;
DWORD dwSize = 0;
DWORD dwRetVal = 0;
int nRVal = 0;
unsigned int i;
/* variables used for GetIfTable and GetIfEntry */
MIB_IFTABLE *pIfTable;
MIB_IFROW *pIfRow;
// Allocate memory for our pointers.
pIfTable = (MIB_IFTABLE *)malloc(sizeof(MIB_IFTABLE));
if (pIfTable == NULL) {
return 0;
}
// Make an initial call to GetIfTable to get the
// necessary size into dwSize
dwSize = sizeof(MIB_IFTABLE);
dwRetVal = GetIfTable(pIfTable, &dwSize, FALSE);
if (dwRetVal == ERROR_INSUFFICIENT_BUFFER) {
free(pIfTable);
pIfTable = (MIB_IFTABLE *)malloc(dwSize);
if (pIfTable == NULL) {
return 0;
}
dwRetVal = GetIfTable(pIfTable, &dwSize, FALSE);
}
if (dwRetVal != NO_ERROR)
goto done;
// Convert input pcap device name to a wide string for compare
{
size_t stISize,stOSize;
stISize = strlen(d->name) + 1;
wszWideName = malloc(stISize * sizeof(wchar_t));
if (!wszWideName)
goto done;
mbstowcs_s(&stOSize,wszWideName,stISize, d->name, stISize);
}
for (i = 0; i < pIfTable->dwNumEntries; i++) {
pIfRow = (MIB_IFROW *)& pIfTable->table[i];
if (!compare_guid(wszWideName, pIfRow->wszName)){
if (pIfRow->dwPhysAddrLen != 6)
continue;
memcpy(mac_addr, pIfRow->bPhysAddr, 6);
nRVal = 1;
break;
}
}
done:
if (pIfTable != NULL)
free(pIfTable);
pIfTable = NULL;
if (wszWideName != NULL)
free(wszWideName);
wszWideName = NULL;
return nRVal;
}

STM32F4 - USART - Receive data array - reads only first frame

today I'm fighting with controlling my uC from the PC.
On a button click, I'm sending data to uC which is to change some values in the program. First of all, the problem is that my program reads only first frame received. Secondly, my program gets stuck when I reinitialize PDM_Filter Structure
What is important - Rx buffer of USART is 16-bit.
Data format is like 6x byte (uint8) that are:
0) ASCII symbol - ! or # or & - symbol indicates what happens next;
1) mic_gain; 2)3) HP Filter cutoff freq; 4)5) LP Filter cutoff freq
So I am receiving 3 x uint16
How it looks like on uC code:
union
{
uint16_t szes[3];
uint8_t os[6];
}RxBuffer;
Interrupt Handler - I had cut the part that works just fine.
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
{
j=0;
while (j<3)
{
RxBuffer.szes[j] = USART_ReceiveData(USART1);
j++;
}
if(RxBuffer.os[0] == 39)
{
DoFlag = false;
I2S_Cmd(SPI2, DISABLE);
//_PDM(sampling_frequency, RxBuffer.szes[2], RxBuffer.szes[1]);
Filter.HP_HZ = RxBuffer.szes[1];
Filter.LP_HZ = RxBuffer.szes[2];
PDM_Filter_Init(&Filter);
GPIO_SetBits(GPIOD, LED_Blue);
mic_gain = RxBuffer.os[1];
Delay(1000);
GPIO_ResetBits(GPIOD, LED_Blue);
I2S_Cmd(SPI2, ENABLE);
DoFlag = true;
}
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
}
}
How intialization of PDM_Filter structure (from libPDMFilter_Keil.lib) looks for me:
Filter.Fs = frequency_s;
Filter.HP_HZ = high_pass_cutoff;
Filter.LP_HZ = low_pass_cutoff;
Filter.In_MicChannels = 1;
Filter.Out_MicChannels = 1;
PDM_Filter_Init(&Filter);
I'm trying to change cutoff frequencies - in order to do so, I reinitialize structure.

Get description of network adapter using Swift [duplicate]

I am trying to get a list of active network interfaces with end user understandable names. Like the names listed in System Preferences instead of en0 en5.
I have the raw interfaces using getifaddrs but haven't been able to find how to take those and get the system names of Ethernet or Wifi.
Anyone know how to do this? This would be for macOS.
What I have now:
struct ifaddrs *ifap;
if( getifaddrs(&ifap) == 0 ){
struct ifaddrs *interface;
for (interface = ifap; interface != NULL; interface = interface->ifa_next) {
unsigned int flags = interface->ifa_flags;
struct sockaddr *addr = interface->ifa_addr;
// Check for running IPv4, IPv6 interfaces. Skip the loopback interface.
if ((flags & (IFF_UP|IFF_RUNNING|IFF_LOOPBACK)) == (IFF_UP|IFF_RUNNING)) {
if (addr->sa_family == AF_INET || addr->sa_family == AF_INET6) {
// Convert interface address to a human readable string:
char host[NI_MAXHOST];
getnameinfo(addr, addr->sa_len, host, sizeof(host), NULL, 0, NI_NUMERICHOST);
printf("interface:%s, address:%s\n", interface->ifa_name, host);
// MAGIC HERE TO CONVERT ifa_name to "Ethernet" or something
}
}
}
freeifaddrs(ifap);
This is possible with System Configuration on macOS. In Objective-C like so:
CFArrayRef ref = SCNetworkInterfaceCopyAll();
NSArray* networkInterfaces = (__bridge NSArray *)(ref);
for(int i = 0; i < networkInterfaces.count; i += 1) {
SCNetworkInterfaceRef interface = (__bridge SCNetworkInterfaceRef)(networkInterfaces[i]);
CFStringRef displayName = SCNetworkInterfaceGetLocalizedDisplayName(interface);
CFStringRef bsdName = SCNetworkInterfaceGetBSDName(interface);
NSLog(#"Name:%# \ninterface: %#\nbsd:%#",displayName, SCNetworkInterfaceGetInterfaceType(interface), bsdName);
}
The localized display name will be something like Display Ethernet or WiFi and the BSD name will be something like en5 which will allow matching to the above code.
This approach doesn't work on iOS, but there aren't really any other configurations on iOS anyway.

Arduino Mega to 2x UNO over Serial

Hi This is my first time posting, so bear with me.
My problem is with the serial communication between the Arduino Mega and 2x Arduino UNO's.
My setup comprises of a Mega as my master device and 1x UNO + Adafruit sound shield & 1x UNO + Adafruit Motor Shield. I have them via serial port i.e Serial1 RxTx on the mega to Serial TxRx on the UNO and same again for Serial2 for the other UNO, (I have x2 UNO's as both sheilds take up the whole PWM pin of the UNO)
Serial.begin(9600); //<--mega//
Serial1.begin(9600); //<--mega//
Serial2.begin(9600); //<--mega//
Serial.begin(9600); //<--UNO Sound//
Serial.begin(9600); //<--UNO motor//
Mega code:
Serial.println("Entering While loop1"); // Debug //
while(CommFlag1 == 0){
while (Serial2.available()){
SerialReceive2 = Serial2.read();
RxContent2.concat(SerialReceive2); //Store Content of Serial Data into Global Variable//
delay(10);
}
Serial.print("Sound MCU: "); // Debug //
Serial.println(RxContent2); // Debug //
delay(100); // Debug //
if (RxContent2 == "Alive$$$") {
Serial2.println("CommEst");
Serial.println("Alive Response Recieved Sound MCU"); // Debug //
RxContent2 = "";
CommFlag1 = 1;
}
}
Serial.println("Entering While loop2"); // Debug //
while(CommFlag2 == 0){
while (Serial1.available()){
SerialReceive1 = Serial1.read(); //Store Content of Serial Data into Global Variable//
RxContent1.concat(SerialReceive1);
delay(10);
}
Serial.print("Motor MCU: "); // Debug //
Serial.println(RxContent1); // Debug //
delay(100); // Debug //
if (RxContent1 == "Alive"){
Serial1.println("CommEst");
Serial.println("Alive Response Recieved Motor MCU");
RxContent1 = "";
CommFlag2 = 1;
}
}
UNO Code(Both are the same except the Serial.print statement which is Alive for the motor):
Serial.println("Alive$$$");
while(CommFlag == 0){
delay(250);
while (Serial.available()){
SerialReceive = Serial.read();
RxContent.concat(SerialReceive);
delay(50);
if (RxContent == "CommEst"){
CommFlag = 1;
RxContent = "";
}
}
}
In the serial window I can see the UNO's "alive$$$" response when PC is connected to the USB (Serial) on the mega, but the mega doesn't seem to accept the response value and doesn't execute the if statement?
Am I doing something wrong? Any help would be greatly appreciated!
Rich
In UNO code you send string by using Serial.println(), That means the string is prefix by \r\n character. But when you compare is not ending with \r\n. Please change if statement by add \r\n at the end of compare string.
if (RxContent2 == "Alive$$$\r\n")
and
if (RxContent1 == "Alive\r\n")
Or change code in UNO to print not println
Serial.print("Alive$$$");
and
Serial.print("Alive");