Setting the vector length in SystemC with a received parameter - systemc

Im making a xor gate in SystemC, from the binding of four NAND gates. I want the module to receive a vector of N bits, where N is passed as parameter. I should be able to perform & and not bitwise operations (for the NAND gate).
The best solution may be using sc_bv_base type, but I don't know how to initialize it in the constructor.
How can I create a bit vector using a custom length?

A way to parameterise the module is to create a new C++ template for the module.
In this example, the width of the input vector can be set at the level of the instantiation of this module
#ifndef MY_XOR_H_
#define MY_XOR_H_
#include <systemc.h>
template<int depth>
struct my_xor: sc_module {
sc_in<bool > clk;
sc_in<sc_uint<depth> > din;
sc_out<bool > dout;
void p1() {
dout.write(xor_reduce(din.read()));
}
SC_CTOR(my_xor) {
SC_METHOD(p1);
sensitive << clk.pos();
}
};
#endif /* MY_XOR_H_ */
Note that the struct my_xor: sc_module is used i.s.o. the SC_MODULE macro. (See page 40 , 5.2.5 SC_MODULE of the IEEE Std 1666-2011).
You can test this with the following testbench:
//------------------------------------------------------------------
// Simple Testbench for xor file
//------------------------------------------------------------------
#include <systemc.h>
#include "my_xor.h"
int sc_main(int argc, char* argv[]) {
const int WIDTH = 8;
sc_signal<sc_uint<WIDTH> > din;
sc_signal<bool> dout;
sc_clock clk("clk", 10, SC_NS, 0.5); // Create a clock signal
my_xor<WIDTH> DUT("my_xor"); // Instantiate Device Under Test
DUT.din(din); // Connect ports
DUT.dout(dout);
DUT.clk(clk);
sc_trace_file *fp; // Create VCD file
fp = sc_create_vcd_trace_file("wave"); // open(fp), create wave.vcd file
fp->set_time_unit(100, SC_PS); // set tracing resolution to ns
sc_trace(fp, clk, "clk"); // Add signals to trace file
sc_trace(fp, din, "din");
sc_trace(fp, dout, "dout");
sc_start(31, SC_NS); // Run simulation
din = 0x00;
sc_start(31, SC_NS); // Run simulation
din = 0x01;
sc_start(31, SC_NS); // Run simulation
din = 0xFF;
sc_start(31, SC_NS); // Run simulation
sc_close_vcd_trace_file(fp); // close(fp)
return 0;
}
Note that I'm using a struct and not a class. A class is also possible.
class my_xor: public sc_module{
public:
The XOR in this code is just the xor_reduce. You can find more about in the IEEE Std 1666-2011 at page 197 (7.2.8 Reduction operators). But I assume this is not the solution you wanted to have.

Related

Addressing pins of Register in microcontrollers

I'm working on Keil software and using LM3S316 microcontroller. Usually we address registers in microcontrollers in form of:
#define GPIO_PORTC_DATA_R (*((volatile uint32_t *)0x400063FC))
My question is how can I access to single pin of register for example, if I have this method:
char process_key(int a)
{ PC_0 = a ;}
How can I get PC_0 and how to define it?
Thank you
Given say:
#define PIN0 (1u<<0)
#define PIN1 (1u<<1)
#define PIN2 (1u<<2)
// etc...
Then:
char process_key(int a)
{
if( a != 0 )
{
// Set bit
GPIO_PORTC_DATA_R |= PIN0 ;
}
else
{
// Clear bit
GPIO_PORTC_DATA_R &= ~PIN0 ;
}
}
A generalisation of this idiomatic technique is presented at How do you set, clear, and toggle a single bit?
However the read-modify-write implied by |= / &= can be problematic if the register might be accessed in different thread/interrupt contexts, as well as adding a possibly undesirable overhead. Cortex-M3/4 parts have a feature known as bit-banding that allows individual bits to be addressed directly and atomically. Given:
volatile uint32_t* getBitBandAddress( volatile const void* address, int bit )
{
__IO uint32_t* bit_address = 0;
uint32_t addr = reinterpret_cast<uint32_t>(address);
// This bit maniplation makes the function valid for RAM
// and Peripheral bitband regions
uint32_t word_band_base = addr & 0xf0000000u;
uint32_t bit_band_base = word_band_base | 0x02000000u;
uint32_t offset = addr - word_band_base;
// Calculate bit band address
bit_address = reinterpret_cast<__IO uint32_t*>(bit_band_base + (offset * 32u) + (static_cast<uint32_t>(bit) * 4u));
return bit_address ;
}
Then you can have:
char process_key(int a)
{
static volatile uint32_t* PC0_BB_ADDR = getBitBandAddress( &GPIO_PORTC_DATA_R, 0 ) ;
*PC0_BB_ADDR = a ;
}
You could of course determine and hard-code the bit-band address; for example:
#define PC0 (*((volatile uint32_t *)0x420C7F88u))
Then:
char process_key(int a)
{
PC0 = a ;
}
Details of the bit-band address calculation can be found ARM Cortex-M Technical Reference Manual, and there is an on-line calculator here.

STM32F769NI USB CDC host problem sending simple data to the device

I am making HID for some data acquisition system. There are a lot of sensors who store test data and when I need I get to them and connect via USB and take it. USB host sent 3 bytes and USB device, if bytes are correct, sends its stored data. Sounds simple.
Previously it was implemented on PC, but now I try to implement it on STM32F769 Discovery and have some serious problems.
I am using ARM Keil 5.27, code generated with STM32CubeMX 5.3.0. I tried just to make a plain simple program, later to integrate with the entire touchscreen interface. I tried to implement this code in main:
if (HAL_GPIO_ReadPin(BUTTON_GPIO_Port, BUTTON_Pin))
while (HAL_GPIO_ReadPin(BUTTON_GPIO_Port, BUTTON_Pin))
{
Transmission_function();
}
And the function itself:
#define DLE 0x10
#define STX 0x2
uint8_t tx_buf[]={DLE, STX, 120}, RX_FLAG;
uint32_t size_tx=sizeof(tx_buf);
void Transmission_function (void)
{
if (Appli_state == APPLICATION_READY)
{
i=0;
USBH_CDC_Transmit(&hUsbHostHS, tx_buf, size_tx);
HAL_Delay(50);
RX_FLAG=0;
}
}
It should send the message after I press the blue button on the Discovery board. All that I get is Hard Fault. While trying to debug, I tried manually to check after which action I get this error and it was functioning in stm32f7xx_ll_usb.c:
HAL_StatusTypeDef USB_WritePacket(USB_OTG_GlobalTypeDef *USBx, uint8_t *src,
uint8_t ch_ep_num, uint16_t len, uint8_t dma)
{
uint32_t USBx_BASE = (uint32_t)USBx;
uint32_t *pSrc = (uint32_t *)src;
uint32_t count32b, i;
if (dma == 0U)
{
count32b = ((uint32_t)len + 3U) / 4U;
for (i = 0U; i < count32b; i++)
{
USBx_DFIFO((uint32_t)ch_ep_num) = *((__packed uint32_t *)pSrc);
pSrc++;
}
}
return HAL_OK;
}
But trying to scroll back in disassembly I notice, that just before Hard Fault program was in this function inside stm32f7xx_hal_hcd.c, in case GRXSTS_PKTSTS_IN:
static void HCD_RXQLVL_IRQHandler(HCD_HandleTypeDef *hhcd)
{
USB_OTG_GlobalTypeDef *USBx = hhcd->Instance;
uint32_t USBx_BASE = (uint32_t)USBx;
uint32_t pktsts;
uint32_t pktcnt;
uint32_t temp;
uint32_t tmpreg;
uint32_t ch_num;
temp = hhcd->Instance->GRXSTSP;
ch_num = temp & USB_OTG_GRXSTSP_EPNUM;
pktsts = (temp & USB_OTG_GRXSTSP_PKTSTS) >> 17;
pktcnt = (temp & USB_OTG_GRXSTSP_BCNT) >> 4;
switch (pktsts)
{
case GRXSTS_PKTSTS_IN:
/* Read the data into the host buffer. */
if ((pktcnt > 0U) && (hhcd->hc[ch_num].xfer_buff != (void *)0))
{
(void)USB_ReadPacket(hhcd->Instance, hhcd->hc[ch_num].xfer_buff, (uint16_t)pktcnt);
/*manage multiple Xfer */
hhcd->hc[ch_num].xfer_buff += pktcnt;
hhcd->hc[ch_num].xfer_count += pktcnt;
if ((USBx_HC(ch_num)->HCTSIZ & USB_OTG_HCTSIZ_PKTCNT) > 0U)
{
/* re-activate the channel when more packets are expected */
tmpreg = USBx_HC(ch_num)->HCCHAR;
tmpreg &= ~USB_OTG_HCCHAR_CHDIS;
tmpreg |= USB_OTG_HCCHAR_CHENA;
USBx_HC(ch_num)->HCCHAR = tmpreg;
hhcd->hc[ch_num].toggle_in ^= 1U;
}
}
break;
case GRXSTS_PKTSTS_DATA_TOGGLE_ERR:
break;
case GRXSTS_PKTSTS_IN_XFER_COMP:
case GRXSTS_PKTSTS_CH_HALTED:
default:
break;
}
}
Last few lines from Dissasembly shows this:
0x080018B4 E8BD81F0 POP {r4-r8,pc}
0x080018B8 0000 DCW 0x0000
0x080018BA 1FF8 DCW 0x1FF8
Why it fails? How could I fix it? I do not have much experience with USB protocol.
I will post my walkaround this, but I am not sure why it worked. Solution was to use EXTI0 interrupt instead of just detection if PA0 is high, as I showed I used here:
if (HAL_GPIO_ReadPin(BUTTON_GPIO_Port, BUTTON_Pin))
while (HAL_GPIO_ReadPin(BUTTON_GPIO_Port, BUTTON_Pin))
Transmission_function();
I changed it to this:
void EXTI0_IRQHandler(void)
{
/* USER CODE BEGIN EXTI0_IRQn 0 */
if(Appli_state == APPLICATION_READY){
USBH_CDC_Transmit(&hUsbHostHS, Buffer, 3);
}
/* USER CODE END EXTI0_IRQn 0 */
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
/* USER CODE BEGIN EXTI0_IRQn 1 */
/* USER CODE END EXTI0_IRQn 1 */
}

Clock type in SC_CTHREAD

I've read that SC_CTHREAD works only with bool, like:
SC_MODULE(my_module){
sc_in<bool> clk;
// ...
void foo();
// ...
SC_CTOR(my_module){
SC_CTHREAD(foo, clk.pos());
}
}
But what if I have sc_in_clk clk in my module, like it is in this example: http://www.asic-world.com/systemc/process3.html? After such simulation the result of the function is not calculated, so I'm using SC_METHOD(foo); sensitive << clk.pos();.
My question is: how can I use sc_in_clk type and SC_CTHREAD both at the same time? Do I need to cast clk to bool somehow?
Yes you can use it both at the same time because sc_in_clk is merely a typedef of sc_in<bool>. That means it doesn't matter whether you use sc_in_clk or sc_in<bool> with SC_CTHREAD.
From the documentation:
typedef sc_in<bool> sc_in_clk;
The typedef sc_in_clk is provided for convenience when adding clock inputs to a module and for backward compatibility with earlier versions of SystemC. An application may use sc_in_clk or sc_in< bool > interchangeably.
I tried to reproduce your problem in my own environment (SystemC 2.3.2). Based on the snippet you posted, I created this small SystemC program:
#include <systemc.h>
SC_MODULE(my_module)
{
sc_in_clk clk;
void foo();
SC_CTOR(my_module)
{
SC_CTHREAD(foo, clk.pos());
}
};
void my_module::foo()
{
while(1)
{
cout << sc_time_stamp() << endl;
wait();
}
}
my_module *DUT;
int sc_main(int argc, char** argv){
sc_clock clk("clk", 10, SC_NS);
DUT = new my_module("my_module");
DUT->clk(clk);
sc_start(50, SC_NS);
return 0;
}
This code works as expected and the output is:
0 s
10 ns
20 ns
30 ns
40 ns
You can try to match the structure of your code to the structure of the program above to find potential other bugs in your code.
What is the structure of your void foo()? Does it contain any form of the wait function, other than void wait(); or void wait(int);? Because a clocked thread process may only call these two forms of wait.

SC_THREAD does not get triggered by its sensitivity list

I am developing a simple NAND module in SystemC. By specification, it should have a 4 ns delay so I tried to describe it with a process with a "wait" statement and SC_THREAD, as follows:
//file: nand.h
#include "systemc.h"
SC_MODULE(nand2){
sc_in<bool> A, B;
sc_out<bool> F;
void do_nand2(){
bool a, b, f;
a = A.read();
b = B.read();
f = !(a && b);
wait(4, SC_NS);
F.write(f);
}
SC_CTOR(nand2){
SC_THREAD(do_nand2);
sensitive << A << B;
}
};
To simulate I've created another module the outputs the stimulus for the NAND, as follows:
//file: stim.h
#include "systemc.h"
SC_MODULE(stim){
sc_out<bool> A, B;
sc_in<bool> Clk;
void stimGen(){
wait();
A.write(false);
B.write(false);
wait();
A.write(false);
B.write(true);
wait();
A.write(true);
B.write(true);
wait();
A.write(true);
B.write(false);
}
SC_CTOR(stim){
SC_THREAD(stimGen);
sensitive << Clk.pos();
}
};
Having these two modules described, the top module (where sc_main is) looks like this:
//file: top.cpp
#include "systemc.h"
#include "nand.h"
#include "stim.h"
int sc_main(int argc, char* argv[]){
sc_signal<bool> ASig, BSig, FSig;
sc_clock Clk("Clock", 100, SC_NS, 0.5);
stim Stim("Stimulus");
Stim.A(ASig); Stim.B(BSig); Stim.Clk(Clk);
nand2 nand2("nand2");
nand2.A(ASig); nand2.B(BSig); nand2.F(FSig);
sc_trace_file *wf = sc_create_vcd_trace_file("sim");
sc_trace(wf, Stim.Clk, "Clock");
sc_trace(wf, nand2.A, "A");
sc_trace(wf, nand2.B, "B");
sc_trace(wf, nand2.F, "F");
sc_start(400, SC_NS);
sc_close_vcd_trace_file(wf);
return 0;
}
The code was compiled and simulated with no errors, however when visualizing the .vcd file in gtkwave the output (F) gets stuck in 1, only showing the delay in the beginning of the simulation.
To test if there were any errors in the code I removed the "wait" statements and changed SC_THREAD to SC_METHOD in the nand.h file and simulated again, now getting the correct results, but without the delays of course.
What am I doing wrong?
It's best if you use an SC_METHOD for process do_nand2, which is sensitive to the inputs. A thread usually has an infinite loop inside of it and it runs for the entire length of the simulation. A method runs only once from beginning to end when triggered. You use threads mostly for stimulus or concurrent processes and threads may, or may not be sensitive to any events.
Just solved the problem:
instead of using
wait(4, SC_NS);
with SC_THREAD I used
next_trigger(4, SC_NS);
with SC_METHOD and it worked just fine.

Handle GPIO in User Space ARM9 Embedded Linux AM1808

I have to interface my GSM module with the AM1808 based on ARM9.
I have assigned all the GPIO pins to the Da850.c as well as mux.h files. I successfully created a uImage and inserted that image in my flash.
I need to handle some of that GPIO from User application.
I know that we can handle the GPIO from the Kerel space but i need to handle from the user space.
As for example I have assigned a GPIO for power key to GSM module. I need to change the pin means (HIGH or LOW) through application.
Ok i have written a following code to access it from the User Space,
#include <stdio.h>
#include <time.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <unistd.h>
#include "GSMpwr.h"
#define BS_GSM_PWR_REGISTER 0x01E26014
#define BS_DCDS_MASK 0x00000004
int fd; // Memory device descriptor
unsigned long *pPWR;
unsigned short GetGSMpwr(void)
{
#if defined __HOST_ARM
unsigned long dcd_value = *pPWR;
return (pwr_value >> 7) & 0x01;
#endif
}
void InitializeGSMpwr(void)
{
#if defined __HOST_ARM
int page_size = getpagesize();
unsigned int MAP_addr;
unsigned int reg_addr;
unsigned char *pTemp; // Pointer to GSMpwr register
/*
* Open memory and get pointer to GSMpwr register in the FPGA
*/
if((fd = open("/dev/mem", O_RDWR | O_SYNC)) < 0)
{
printf("failed to open /dev/mem");
return;
}
else
{
MAP_addr = (BS_GSM_PWR_REGISTER & ~(page_size - 1));
pTemp = (unsigned char *)mmap(NULL, page_size,(PROT_READ | PROT_WRITE),MAP_SHARED,fd,MAP_addr);
if((pTemp == MAP_FAILED) || (pTemp == NULL))
{
printf("failed to map /dev/mem");
return;
}
else
{
printf(“Memory Mapped at Address %p. \n”,pTemp);
}
virt_addr = map_base + (control & MAP_MASK);
reg_addr = (BS_GSM_PWR_REGISTER & (page_size - 1));
pPWR = (unsigned long*)(pTemp + reg_addr);
printf("GSM PWR PIN mapped in Application\n");
}
I can only read that pin through this code, Now i want to use that pin as an output and want to go high and low with the time interval of 3sec.
The easiest way is to utilize GPIO support in sysfs, where you could control all the exported GPIO's. Please have a look at the Linux kernel GPIO documentation, in particular, Sysfs Interface for Userspace part.
After you have enabled GPIO support in sysfs (GPIO_SYSFS), the GPIO control would be as easy as:
Example
GPIO=22
cd /sys/class/gpio
ls
echo $GPIO > /sys/class/gpio/export
ls
Notice on the first ls that gpio22 doesn't exist, but does after you export GPIO 22 to user space.
cd /sys/class/gpio/gpio$GPIO
ls
There are files to set the direction and retrieve the current value.
echo "in" > direction
cat value
You can configure the GPIO for output and set the value as well.
echo "out" > direction
echo 1 > value
Example is taken from here.
I got it please find following code for that,I got the Specific pin address and i have accessed that pin like,
unsigned short GetGSMpwr(void)
{
unsigned long pwr_value = *pPWR;
printf("GSM_PWR:check Start : %ld",pwr_value);
return (pwr_value >> 1) & 0x01;
}
unsigned short SetGSMpwr(void)
{
unsigned long pwr_value = *pPWR;
printf("GSM_PWR:check Start : %ld",pwr_value);
*pPWR = ~((pwr_value >> 1) & 0x01);
}
unsigned short ClrGSMpwr(void)
{
unsigned long pwr_value = *pPWR;
printf("GSM_PWR:check Start : %ld",pwr_value);
*pPWR = 256;
}`