I am trying to code an Interrupt Handler in C++ without the use of Assembly through __attribute__((interrupt)).
Following code:
init/idt.cpp:
void set(IDTDescr *descriptor, void(*handler)(void), uint8_t flags)
{
descriptor->selector = 0x08;
uintptr_t handler_addr = (uintptr_t)handler;
descriptor->offset_1 = handler_addr & 0xFFFF;
descriptor->offset_2 = (handler_addr >> 16) & 0xFFFF;
descriptor->offset_3 = (handler_addr >> 32) & 0xFFFFFFFF;
descriptor->flags = flags;
}
void init(void)
{
memset(descriptors, 0, sizeof(descriptors));
//Faults:
set(&descriptors[0x00], &DivideByZero, IDT_PRESENT | IDT_INTERRUPT);
set(&descriptors[0x01], &Debug, IDT_PRESENT | IDT_INTERRUPT);
and so on.
interrupt/handler/stubs.h:
//Faults:
void DivideByZero(struct cpu_state *state);
void Debug(struct cpu_state *state);
and so on.
interrupt/handler/fault_irs.cpp:
__attribute__((interrupt)) void DivideByZero(struct cpu_state *state)
{
Text::Clear();
Text::Simple::Write("FAULT!");
abort();
}
__attribute__((interrupt)) void Debug(struct cpu_state *state)
{
Text::Clear();
Text::Simple::Write("FAULT!");
abort();
}
and so on.
The problem is that GCC tells me that i can't call a ISR directly. But i don't call it directly, do I? Do I have to define __attribute__((interrupt)) in void set too?
Would it maybe help if i would set the arguments in stubs.h to void?
The funny thing is that the first fault is accepted by gcc...
It seams like gcc wants me to put all isr's in a seperate file... If i do the same in interrupt/handler/irq_irs.cpp it works....
Maybe an additional explanation why i don't want to simply use a single Interrupt Handler: If i use a single IH, i'll have to use a switch-case to call the right function for handling the interrupt (because i can't put all of the handling code in the handler i'll have to use seperate functions). That's much overhead and doesn't really make things simpler... Even if i really have to create a file for 256 interrupts...
Related
I was reading an article regarding bare bones programming of ARM processor when I came across the following code
struct systick {
volatile uint32_t CTRL, LOAD, VAL, CALIB;
};
#define SYSTICK ((struct systick *) 0xe000e010)
#define BIT(x) (1UL << (x))
static inline void systick_init(uint32_t ticks) {
if ((ticks - 1) > 0xffffff) return; // Systick timer is 24 bit
SYSTICK->LOAD = ticks - 1;
SYSTICK->VAL = 0;
SYSTICK->CTRL = BIT(0) | BIT(1) | BIT(2); // Enable systick
RCC->APB2ENR |= BIT(14); // Enable SYSCFG
}
I am not able to understand how does initializing a pointer to a structure initialize variables inside a structure? Does the ARM compiler treat it as an enum?
Thanks!
It's very likely a memory-mapped device. So, when you write to structure members, you're essentially manipulating the hardware, just as with port output (but in this case, memory-mapped). So you're essentially writing to a hardware that's available on addresses 0xe000e010, 0xe000e014, 0xe000e018, 0xe000e01c respectively for CTRL, LOAD, VAL, CALIB. Then you set particular bits manually.
I am writing a bootloader for an STM32, where I need to jump from bootloader to the real app.
In C this works, because I can cast an address to a void pointer and assign that to a function pointer, and call the function pointer as follows:
void jump_to_firmware(uint32_t address)
{
uint32_t reset_handler_add = *((volatile uint32_t *)(address + 4));
void (*app_reset_handler)(void) = (void *)reset_handler_add;
SCB->VTOR = address;
uint32_t msp_value = *((volatile uint32_t *)address);
__set_MSP(msp_value);
app_reset_handler();
}
If I use the same implementation in a C++ the gnu compiler will give an error on the cast to void pointer.
include/bootloader.hpp:58:39: error: invalid conversion from 'void*'
to 'void (*)()' [-fpermissive]
After googling I found this SO page, which I tried and came to the following implementation in my class:
void JumpToApp()
{
// Quick test if C style cast does work
//jump_to_firmware(_appStartAddress);
uint32_t mspAdress = *((volatile uint32_t *)_appStartAddress);
uint32_t resetHandlerAddress = *((volatile uint32_t *)(_appStartAddress + sizeof(uint32_t)));
// https://stackoverflow.com/questions/1096341/function-pointers-casting-in-c
typedef void (*functionPointer)();
functionPointer resetHandler = 0;
reinterpret_cast<void*&>(resetHandler) = (void*)resetHandlerAddress;
SCB->VTOR = _appStartAddress;
__set_MSP(mspAdress);
resetHandler();
}
In the C++ implementation:
functionPointer resetHandler is assigned with 0x8035065
SCB->VTOR is assigned with 0x08020000
mspAddress is assigned with `0x20020000
then the function pointer resetHandler is called
In the C implementation:
app_reset_handler is assigned with 0x8035065
SCB->VTOR is assigned with 0x08020000
mspAddress is assigned with `0x20020000
then the function pointer app_reset_handler is called
The C implementation works, it jumps to my app, the app runs without issues.
The C++ implementation ends up nowhere. It hangs/crashes on the following (to me meaningless) address:
I am trying to keep the amount of source files to a minimum, so I would like to keep the logic in the single class definition.
My questions:
Did I misunderstand the linked SO page and can somebody see where I went wrong in the C++ implementation?
Is there a better/easier way to cast an address to a function pointer in C++?
Or is there a technical reason why it simply can't be done in C++?
PS: The bootloader code is the same in both cases. The only difference I made to test either implementation is to comment out the code in Bootloader::JumpToApp and call the C function jump_to_firmware(uint32_t) instead.
PPS: all peripherals are deinitialized properly. Again, it works fine, the problem only appears when I use this C++ implementation.
The same code will compile in C and C++. You simple has to cast to the correct cast (in C++ you cant assign a void * to non void * pointer. It is much more strict than in C.
void jump_to_firmware(uint32_t address)
{
uint32_t reset_handler_add = *((volatile uint32_t *)(address + 4));
void (*app_reset_handler)(void) = (void (*)(void))reset_handler_add;
/* ... */
}
If you do not like those weird casts you can typedef the function.
typedef void handler(void);
void jump_to_firmware(uint32_t address)
{
uint32_t reset_handler_add = *((volatile uint32_t *)(address + 4));
handler *app_reset_handler = (handler *)reset_handler_add;
/* ... */
}
In my understanding, DeviceIOControl and ioctl are the same functions. They both send control codes to the hardware and return the responses. In an effort to reuse code, I am trying to create a function which will work in a cross-platform manner. Therefore, I've decided to use the DeviceIOControl api since it is fixed and specific. The problem is: how do I map ioctl to that?
I currently have:
int DeviceIoControl_issueCommand(DeviceHandle handle, int command, void *input, ssize_t sizeof_input, void *output, ssize_t sizeof_output, uint32_t *bytes_written){
#if SYSTEMINFORMATION_ISWINDOWS
int result = DeviceIoControl(handle,command,input,sizeof_input,output,sizeof_output,bytes_written,0);
if (result == 0){
result = -1; //-1 is the new error return
}
return result;
#else
int result = ioctl(handle, command, input); //this doesnt work!
return result;
#endif
}
Any help is greatly appreciated!
What you are asking is not possible without a lot of internal translation in DeviceIoControl_issueCommand. The function calls are completely different and expect different parameters and data. You can work around this by declaring an IOControl class and adding member functions for each type of IO functionality you want to support.
class IOControl
{
public:
void DoIoControlX();
void DoIoControlY(int param1, int param2);
};
Then provide an impelementation for each platform you need to support. One for Windows DeviceIOControl calls and one for systems that support ioctl
I actually found that there is an IOCTL which does pass raw data to and from the driver (at least for the hard drive): HDIO_DRIVE_TASKFILE (http://www.mjmwired.net/kernel/Documentation/ioctl/hdio.txt)
I've been trying to write a simple VST plugin. It doesn't need any fancy interfaces, just a few controls. But I don't know where to start. Begin huge wall of text.
I've been researching religiously around the net for information and guides on this topic, but the best I've found so far is this and this page. While they're good, I can't seem to recreate a program using those sources.
For reference, I'm using VST SDK 3.5.2 and MSVC 2010.
I added the folder \public.sdk\source\vst2.x to my project (which includes the source for audioeffect & vstplugmain). I really wish there was somewhere a simple bullet point list of what you need to do to get a working VST plugin effect working / exporting correctly etc.
The first two links I provided walk it through nicely, but it seems the method for creating a VST has changed since then. This is the skeleton of my program, which, while it compiles, won't get recognized by my VST host (error upon loading).
harmonicmodulator.h
#include "public.sdk\source\vst2.x\audioeffectx.h"
namespace Steinberg {
namespace VST {
class HarmonicModulator : public AudioEffectX {
public:
/* ?? what about createEffectInstance
static FUnknown* createInstance (void* context) {
return (IAudioProcessor*)new HarmonicModulator;
}
*/
HarmonicModulator(audioMasterCallback master);
virtual ~HarmonicModulator(); //can't hurt
/*
virtuals
*/
virtual void process (float **inputs, float **outputs, VstInt32 sampleFrames);
virtual void processReplacing (float **inputs, float **outputs, VstInt32 sampleFrames);
virtual void setProgramName (char *name);
virtual void getProgramName (char *name);
virtual void setParameter (VstInt32 index, float value);
virtual float getParameter (VstInt32 index);
virtual void getParameterLabel (VstInt32 index, char *label);
virtual void getParameterName (VstInt32 index, char *label);
virtual void getParameterDisplay (VstInt32 index, char *text);
virtual bool getEffectName (char * name);
virtual bool getVendorString (char * text);
virtual bool getProductString (char * text);
virtual VstInt32 getVendorVersion () { return 1000; }
virtual VstPlugCategory getPlugCategory () { return kPlugCategEffect; }
protected:
char progname[64];
float fparam;
};
}
}
harmonicmodulator.cpp
#include "HarmonicModulator.h"
namespace Steinberg {
namespace VST {
/*
Implementation for the constructor.
*/
HarmonicModulator::HarmonicModulator(audioMasterCallback cb) : AudioEffectX(cb, 1, 1), fparam(0.f) {
setNumInputs (2); // stereo in
setNumOutputs (2); // stereo out
setUniqueID ('HMXX'); // identify
canProcessReplacing (); // supports both accumulating and replacing output
strcpy_s(progname, "Default");
}
/*
Implementation for the destructor.
*/
HarmonicModulator::~HarmonicModulator() {}
/*
ProcessReplacing
*/
void HarmonicModulator::processReplacing (float **inputs, float **outputs, VstInt32 sampleFrames) {
float *in1 = inputs[0];
float *in2 = inputs[1];
float *out1 = outputs[0];
float *out2 = outputs[1];
while (--sampleFrames >= 0) {
(*out1++) += (*in1++);
(*out2++) += (*in2++);
}
}
/*
Process
*/
void HarmonicModulator::process (float **inputs, float **outputs, VstInt32 sampleFrames) {
float *in1 = inputs[0];
float *in2 = inputs[1];
float *out1 = outputs[0];
float *out2 = outputs[1];
while (--sampleFrames >= 0) {
(*out1++) += (*in1++);
(*out2++) += (*in2++);
}
}
/*
Below seems to be needed to work
*/
void HarmonicModulator::setProgramName (char *name){
strcpy_s(progname, name);
}
void HarmonicModulator::getProgramName (char *name){
strcpy_s(name, 32, progname);
}
void HarmonicModulator::setParameter (VstInt32 index, float value) {
fparam = value;
}
void HarmonicModulator::getParameterLabel (VstInt32 index, char *label) {
strcpy_s(label, 32, "dB");
}
void HarmonicModulator::getParameterName (VstInt32 index, char *label) {
strcpy_s(label, 32, "Volume");
}
void HarmonicModulator::getParameterDisplay (VstInt32 index, char *text) {
this->dB2string(fparam, text, 32);
}
//-----------------------------------------------------------------------------------------
float HarmonicModulator::getParameter (VstInt32 index) {
return fparam;
}
bool HarmonicModulator::getEffectName (char * name) {
strcpy_s(name, 32, "Harmonic Modulator");
return true;
}
bool HarmonicModulator::getVendorString (char * text) {
strcpy_s(text, 32, "LightBridge");
return true;
}
bool HarmonicModulator::getProductString (char * text) {
strcpy_s(text, 32, "Harmonic Modulator");
return true;
}
}
}
AudioEffect* createEffectInstance (audioMasterCallback audioMaster) {
return new Steinberg::VST::HarmonicModulator (audioMaster);
}
Okay, the "method" I'mm using is: According to both of the previous guides, to make a successful plugin, you at least need to derive your plugin from audio effectx and override process() and processReplacing() which do the actual processing.
The rest was added in hope that it would do something. Moreover, the exported function createEffectInstance() returns a new instance of the plugin. vstplugmain.cpp holds a dllmain and an exported function VstPlugMain that receives an audiomastercallback and returns createEffectInstance(callback).
IMO, that seems like a working method and a re-creation (as far as I can see) of the two guides provided earlier. The plugin is defined and there's an interface between plug and host that allows to create instances of it. What am I missing? The guide says that's all you need.
Is this a difference between different versions of VST? 2/3?
So I couldn't get the VstPluginTestHost bundled to work, it couldn't locate my VST. I tried the validator, and stepping through that, I found that since my program doesn't export a function called GetPluginFactory, it's discarded. Okay, understandable, but none of the guides tell anything about this.
Searching through endless amounts of source, it seems some VST sources add this cryptic passage at the bottom (code taken from AGainSimple.cpp):
BEGIN_FACTORY_DEF ("Steinberg Media Technologies",
"http://www.steinberg.net",
"mailto:info#steinberg.de")
//---First Plugin included in this factory-------
// its kVstAudioEffectClass component
DEF_CLASS2 (INLINE_UID (0xB9F9ADE1, 0xCD9C4B6D, 0xA57E61E3, 0x123535FD),
PClassInfo::kManyInstances, // cardinality
kVstAudioEffectClass, // the component category (don't change this)
"AGainSimple VST3", // here the Plug-in name (to be changed)
0, // single component effects can not be destributed so this is zero
"Fx", // Subcategory for this Plug-in (to be changed)
FULL_VERSION_STR, // Plug-in version (to be changed)
kVstVersionString, // the VST 3 SDK version (don't change this, use always this definition)
Steinberg::Vst::AGainSimple::createInstance)// function pointer called when this component should be instantiated
END_FACTORY
Which seems to export an interface that gives the host some basic information and an interface for creating the plugin. BUT. I thought createEffectInstance did this. Now there's a new function called createInstance. Is there a difference? The function signatures suggest createInstance does NOT receive the audiomaster callback, and thus can't instantiate any derivation of AudioEffect (which takes this as an parameter in its constructor) - I provided the function, commented out, in harmonicmodulator.h.
Also, I noticed that many newer sources include another "main" cpp file (dllmain.cpp, in \public.sdk\source\main, that defines exports for InitModule and DeInitModule, but no createEffectInstance anymore. This is dizzying me. They also seem to derive from either AudioEffect (no x) or SingleComponentEffect (seems to be a lot more complicated? lol).
On top of this, I can't seem to get that begin_factory stuff working because of a lot of missing constants and defines that reside in many different files. Are you supposed to add the whole SDL to your project? Thats 6,000 files.
TL;DR
Nothing really works and I can't seem to get a clue. The bundled source samples work, but they all approach the "method" of creating a VST differently. Seriously, any guidance or help will be so appreciated. I'm trying to create this as part of an application, and I got everything else pretty much worked out.
I've been trying to write a simple VST plugin. It doesn't need any
fancy interfaces, just a few controls. But I don't know where to
start. Begin huge wall of text.
Start by compiling the example plugins that come with the SDK. Then duplicate that with your own bare bones plugin. Continue building up from there.
Is this a difference between different versions of VST? 2/3?
VST 2 and VST 3 are different formats. I would recommend building a VST 2.4 plugin unless you have a specific reason for building a VST 3 plguin. VST 2.4 is widely supported by many hosts and will likely continue to be for some years yet. VST 3 is a newer format but not so widely supported.
I use cout statements in my program for debugging purposes. I would like to make a function that works like it, or works like printf, but is sensitive to a global variable. If this global variable is true, then it will print to screen. If it is false, then it won't print anything. Is there already a function like this? If not, then how can it be made?
Something like this:
int myPrintf(const char* format, ...)
{
if (globalCheck == 0)
return 0
va_list vl;
va_start(vl, format);
auto ret = vprintf(format, vl);
va_end(vl);
return ret;
}
va_start and va_end take the arguments in the ... and encapsulate them in a va_list. with this va_list you can then the vprintf which is a variant of printf designed exactly for this need.
Side note - usually it is bad practice to use global variables. A better thing to do is to encapsulate it in a class like this -
class ConditionalPrinter {
public:
ConditionalPrinter() : m_enable(true) {}
void setOut(bool enable) { m_enable = enable; }
int myPrintf(const char* format, ...);
private:
bool m_enable;
}
and then to check m_enable instead of the global variable.
Usage of this looks like this:
ConditionalPrinter p;
p.myPrintf("hello %d", 1); // printed
p.setOut(false);
p.myPrintf("hello2 %d", 1); // not printed
....
Don't write it yourself. Doing it right is much harder then you think. Even harder when you need threads and efficiency. Use one of existing logging libraries like:
glog: http://code.google.com/p/google-glog/ (I prefer this - it is lightweight and do what it needs to do)
Log4cpp http://log4cpp.sourceforge.net/ (powerful and configuration compatible with popular java logging)
... add your favorite to this wiki
As someone else said, there are several good logging frameworks available. However, if you want to roll your own, the first thing to note is that cout isn't a function, it's a stream. The function is operator<<. What you can do is something like the following:
/* trace.h */
extern ostream debug;
void trace_init();
void trace_done();
/* trace.cpp */
#include "trace.h"
ostream debug(cout.rdbuf());
static ofstream null;
void trace_init()
{
null.open("/dev/null");
if(output_is_disabled) { // put whatever your condition is here
debug.rdbuf(null.rdbuf());
}
}
void trace_done()
{
null.close();
}
You might have to adjust a bit if you're on a platform without /dev/null. What this does is let you write
debug << "here's some output << endl;
and if you have the output enabled, it will write to cout. If not, it will write to /dev/null where you won't see anything.
For that matter, you could just set cout's rdbuf to somewhere where you won't see that output, but I would find that to be a really bad idea. Creating new streams gives you a lot more flexibility in controlling your output.