*.test
*.out
*.err
+*.vcd
+*.bmp
--- /dev/null
+../../vfpu/bin/vfpu
\ No newline at end of file
#Makefile
-ARCH := $(shell uname -i)
+ARCH := $(shell uname -m)
CXX = g++ -std=gnu++0x -Wall -Werror -Wshadow -pedantic -g
MAIN = main.o
-OBJ = log.o document.o view.o screen.o
+OBJ = log.o document.o view.o screen.o vfpu.o
LIB_x86_64 = ../contrib/lib/libSDL2-2.0.so.0 -lGL
LIB_i386 = ../contrib/lib32/libSDL2-2.0.so.0 -lGL
-LIB_unknown = $(LIB_x86_64)
+
MAINRPATH_x86_64 = -Wl,-rpath,'$$ORIGIN/../contrib/lib'
MAINRPATH_i386 = -Wl,-rpath,'$$ORIGIN/../contrib/lib32'
TESTRPATH_x86_64 = -Wl,-rpath,'$$ORIGIN/../../contrib/lib'
DEPS := $(OBJPATHS:%.o=%.d)
CFLAGS_x86_64 := -I../contrib/include/SDL2 -I`pwd`
CFLAGS_i386 := -I../contrib/include32/SDL2 -I`pwd`
-CFLAGS_unknown = $(CFLAGS_x86_64)
+
LIB := $(LIB_$(ARCH))
MAINRPATH := $(MAINRPATH_$(ARCH))
}
};
+ struct Colour
+ {
+ float r; float g; float b; float a;
+ Colour() = default;
+ Colour(float _r, float _g, float _b, float _a) : r(_r), g(_g), b(_b), a(_a) {}
+ };
+
struct Objects
{
std::vector<ObjectType> types;
{
Document doc;
srand(time(NULL));
- if (argc > 1)
+
+ enum {OUTPUT_TO_BMP, LOOP} mode = LOOP;
+
+ Rect bounds(0,0,1,1);
+ Colour c(0,0,0,1);
+ const char * input_bmp = NULL;
+ const char * output_bmp = NULL;
+ const char * input_filename = NULL;
+
+ int i = 0;
+ while (++i < argc)
{
- for (int i = 2; i < argc; ++i)
+ if (argv[i][0] != '-')
{
- if (fork() == 0) doc.Load(argv[i]);
+ input_filename = argv[i];
+ continue;
}
- doc.Load(argv[1]);
+ switch (argv[i][1])
+ {
+ case 'o':
+ mode = OUTPUT_TO_BMP;
+ if (++i >= argc)
+ Fatal("No input argument following -o switch");
+ input_bmp = argv[i];
+ if (++i >= argc)
+ Fatal("No output argument following -o switch");
+ output_bmp = argv[i];
+
+ break;
+ case 'c':
+ {
+ Debug("Reading paint colour");
+ for (int j = 1; j <= 4; ++j)
+ {
+ if (i+j >= argc)
+ Fatal("No %d colour component following -c switch", j);
+ char * e;
+ float * comp = (j == 1) ? (&c.r) : ((j == 2) ? (&c.g) : ((j == 3) ? (&c.b) : &(c.a)));
+ *comp = strtof(argv[i+j], &e);
+ if (*e != '\0')
+ Fatal("Colour component %d not a valid float", j);
+ }
+ i += 4;
+ break;
+ }
+ }
+ }
+
+ if (input_filename != NULL)
+ {
+ doc.Load(input_filename);
}
- else
+ else
{
- Debug("Add random object");
- //doc.Add(RECT_FILLED, Rect(Random()*0.5, Random()*0.5, Random()*0.5, Random()*0.5));
- doc.Add(RECT_FILLED, Rect(0.25,0.25, 0.5, 0.5));
+ doc.Add(RECT_FILLED, Rect(0.2,0.2,0.6,0.6));
}
- MainLoop(doc);
+
+ if (mode == LOOP)
+ MainLoop(doc, bounds, c);
+ else if (mode == OUTPUT_TO_BMP)
+ OverlayBMP(doc, input_bmp, output_bmp, bounds, c);
return 0;
}
#include "document.h"
#include "view.h"
#include "screen.h"
+#include <unistd.h>
using namespace std;
using namespace IPDF;
-inline void MainLoop(Document & doc)
+inline void OverlayBMP(Document & doc, const char * input, const char * output, const Rect & bounds = Rect(0,0,1,1), const Colour & c = Colour(0.f,0.f,0.f,1.f))
{
- View view(doc);
+ View view(doc, bounds, c);
Screen scr;
- scr.SetMouseHandler([&](int x, int y, int buttons, int wheel)
+ //view.Render();
+ scr.RenderBMP(input);
+ scr.Present();
+ sleep(5);
+ scr.ScreenShot(output);
+}
+
+inline void MainLoop(Document & doc, const Rect & bounds = Rect(0,0,1,1), const Colour & c = Colour(0.f,0.f,0.f,1.f))
+{
+ View view(doc,bounds, c);
+ Screen scr;
+ scr.SetMouseHandler([&](int x, int y, int buttons, int wheel) // [?] wtf
{
static bool oldButtonDown = false;
static int oldx, oldy;
}
}
);
+
while (scr.PumpEvents())
{
view.Render();
#elif defined REAL_DOUBLE
typedef double Real;
inline double Float(Real r) {return r;}
-#elif defined REAL_HALF
- struct Real
- {
- Real() = default;
- Real(double r) : value(r)
- {
- int & a = *((int*)(&value)); // um...
- // mask out extra bits in exponent
- //1000 1111 1000 0000 0000 0011 1111 1111
- // Endianness matters
- a &= 0xFFC001F1; //0x8F8003FF;
-
- }
-
- Real operator+(float f) const {return Real(value+f);}
- Real operator-(float f) const {return Real(value+f);}
- Real operator/(float f) const {return Real(value/f);}
- Real operator*(float f) const {return Real(value*f);}
- Real operator+(const Real & r) const {return Real(this->value + r.value);}
- Real operator-(const Real & r) const {return Real(this->value - r.value);}
- Real operator*(const Real & r) const {return Real(this->value * r.value);}
- Real operator/(const Real & r) const {return Real(this->value / r.value);}
- Real & operator+=(const Real & r) {this->value += r.value; return *this;}
- Real & operator-=(const Real & r) {this->value -= r.value; return *this;}
- Real & operator/=(const Real & r) {this->value /= r.value; return *this;}
- Real & operator*=(const Real & r) {this->value *= r.value; return *this;}
-
- float value;
- };
- inline float Float(Real r) {return r.value;}
-
- inline std::ostream & operator<<(std::ostream & os, Real & r) {return os << r.value;} // yuk
-
-#endif //REAL_HALF
-
+#endif
}
#endif //_REAL_H
}
m_gl_context = SDL_GL_CreateContext(m_window);
+
+ glClearColor(1.f,1.f,1.f,1.f);
+ glClear(GL_COLOR_BUFFER_BIT);
+ Present();
ResizeViewport(800, 600);
m_mouse_handler(m_last_mouse_x, m_last_mouse_y, 0, evt.wheel.y);
}
break;
+ case SDL_KEYDOWN:
+ {
+ Debug("Key %c down", (char)evt.key.keysym.sym);
+ if (isalnum((char)evt.key.keysym.sym))
+ {
+ char filename[] = "0.bmp";
+ filename[0] = (char)evt.key.keysym.sym;
+ ScreenShot(filename);
+ }
+ }
default:
break;
}
SDL_GL_SwapWindow(m_window);
}
+void Screen::ScreenShot(const char * filename) const
+{
+ Debug("Attempting to save BMP to file %s", filename);
+
+ int w = ViewportWidth();
+ int h = ViewportHeight();
+ unsigned char * pixels = new unsigned char[w*h*4];
+ if (pixels == NULL)
+ Fatal("Failed to allocate %d x %d x 4 = %d pixel array", w, h, w*h*4);
+
+ glReadPixels(0,0,w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+
+ SDL_Surface * surf = SDL_CreateRGBSurfaceFrom(pixels, w, h, 8*4, w*4, 0,0,0,0);
+ if (surf == NULL)
+ Fatal("Failed to create SDL_Surface from pixel data - %s", SDL_GetError());
+
+ GLenum texture_format = (surf->format->Rmask == 0x000000FF) ? GL_RGBA : GL_BGRA;
+ Debug("SDL_Surface %d BytesPerPixel, format %d (RGB = %d, BGR = %d, RGBA = %d, BGRA = %d)", surf->format->BytesPerPixel, texture_format, GL_RGB, GL_BGR, GL_RGBA, GL_BGRA);
+
+ if (SDL_SaveBMP(surf, filename) != 0)
+ Fatal("SDL_SaveBMP failed - %s", SDL_GetError());
+
+ SDL_FreeSurface(surf);
+ delete [] pixels;
+ Debug("Succeeded!");
+}
+
+/**
+ * Render a BMP
+ * NOT PART OF THE DOCUMENT FORMAT
+ */
+void Screen::RenderBMP(const char * filename) const
+{
+ SDL_Surface * bmp = SDL_LoadBMP(filename);
+ if (bmp == NULL)
+ Fatal("Failed to load BMP from %s - %s", filename, SDL_GetError());
+
+ int w = bmp->w;
+ int h = bmp->h;
+
+ GLenum texture_format;
+ switch (bmp->format->BytesPerPixel)
+ {
+ case 4: //contains alpha
+ texture_format = (bmp->format->Rmask == 0x000000FF) ? GL_RGBA : GL_BGRA;
+ break;
+ case 3: //does not contain alpha
+ texture_format = (bmp->format->Rmask == 0x000000FF) ? GL_RGB : GL_BGR;
+ break;
+ default:
+ Fatal("Could not understand SDL_Surface format (%d colours)", bmp->format->BytesPerPixel);
+ break;
+ }
+
+ //Debug("SDL_Surface %d BytesPerPixel, format %d (RGB = %d, BGR = %d, RGBA = %d, BGRA = %d)", bmp->format->BytesPerPixel, texture_format, GL_RGB, GL_BGR, GL_RGBA, GL_BGRA);
+
+
+ GLuint texID;
+ glEnable(GL_TEXTURE_2D);
+ glGenTextures(1, &texID);
+ glBindTexture(GL_TEXTURE_2D, texID);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, bmp->format->BytesPerPixel, w, h, 0, texture_format, GL_UNSIGNED_BYTE, bmp->pixels);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0.0, 1.0, 1.0, 0.0, -1.f, 1.f);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ glBegin(GL_QUADS);
+ glTexCoord2i(0,0); glVertex2f(0,0);
+ glTexCoord2i(1,0); glVertex2f(1,0);
+ glTexCoord2i(1,1); glVertex2f(1,1);
+ glTexCoord2i(0,1); glVertex2f(0,1);
+ glEnd();
+
+ glDisable(GL_TEXTURE_2D);
+ SDL_FreeSurface(bmp);
+}
void Present();
// Get the current width/height of the window's viewport.
- int ViewportWidth() { return m_viewport_width; }
- int ViewportHeight() { return m_viewport_height; }
+ int ViewportWidth() const { return m_viewport_width; }
+ int ViewportHeight() const { return m_viewport_height; }
// Handle mouse input.
typedef std::function<void(int x, int y, int button, int wheel)> MouseHandler;
CursorHand
};
void SetMouseCursor(MouseCursors cursor);
+
+ void ScreenShot(const char * filename) const;
+ void RenderBMP(const char * filename) const;
private:
void ResizeViewport(int width, int height);
--- /dev/null
+#include "main.h"
+
+#include <bitset>
+
+using namespace std;
+
+
+
+int main(int argc, char ** argv)
+{
+ char buffer[BUFSIZ];
+ double input;
+ printf("Enter a double: ");
+ fgets(buffer, BUFSIZ, stdin);
+ sscanf(buffer, "%lf", &input);
+
+
+ float f = (float)(input);
+
+ unsigned long long i;
+ memcpy(&i, &f, 4);
+ bitset<32> b32(i);
+ memcpy(&i, &input, 8);
+ bitset<64> b64(i);
+
+ printf("\nAs float: %s\n", b32.to_string().c_str());
+ printf("\nAs double: %s\n", b64.to_string().c_str());
+ #ifdef REAL_BITSET
+ Real r(input);
+ printf("\nAs real: %s\n", r.repr.to_string().c_str());
+ #endif //REAL_BITSET
+
+}
--- /dev/null
+#include "main.h"
+
+#include "vfpu.h"
+using namespace std;
+
+
+int main(int argc, char ** argv)
+{
+ if (argc > 1)
+ VFPU::Start(argv[1]);
+ else
+ VFPU::Start();
+ float result = VFPU::Exec(25,10, VFPU::SUB);
+ Debug("%f\n", result);
+ VFPU::Halt();
+
+ return 0;
+}
--- /dev/null
+../contrib/vfpu
\ No newline at end of file
--- /dev/null
+#include "vfpu.h"
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/fcntl.h>
+#include <stdbool.h>
+#include <signal.h>
+#include <string.h>
+
+#include <sstream>
+#include <iomanip>
+
+#include "common.h"
+
+using namespace std;
+
+namespace VFPU
+{
+
+static const char g_fpu[] = "vfpu";
+
+static bool g_running = false;
+static int g_fpu_socket[2] = {-1,-1};
+static pid_t g_fpu_pid = -1;
+
+/**
+ * Starts the VFPU
+ * @returns 0 on success, errno of the failing function on failure
+ */
+int Start(const char * vcd_output)
+{
+ assert(!g_running);
+ // create unix socket pair
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, g_fpu_socket) != 0)
+ return errno;
+
+
+ g_fpu_pid = fork();
+ if (g_fpu_pid < 0) // error check
+ return errno;
+
+
+ // Child branch
+ if (g_fpu_pid == 0)
+ {
+
+ // Remap stdio to the socket
+ dup2(g_fpu_socket[0],fileno(stdin));
+ dup2(g_fpu_socket[0],fileno(stdout));
+
+ // Unbuffer things; buffers are a pain
+ setbuf(stdin, NULL); setbuf(stdout, NULL); setbuf(stderr, NULL);
+
+ Debug("Child about to suppress stderr and exec vfpu");
+ dup2(open("/dev/null", O_APPEND), fileno(stderr)); //LALALA I AM NOT LISTENING TO YOUR STUPID ERRORS GHDL
+ if (vcd_output != NULL)
+ {
+ string s("--vcd=");
+ s += vcd_output;
+ execl(g_fpu, g_fpu, s.c_str(), NULL);
+ }
+ else
+ {
+ execl(g_fpu, g_fpu,NULL);
+ }
+ int err = errno; // Because errno will be set again by the next system call
+ Fatal("Uh oh! %s\n", strerror(err)); // We will never see this if something goes wrong... oh dear
+ exit(err); // Child exits here.
+ }
+
+ // Parent branch
+ usleep(100);
+ g_running = true; // We are ready!
+ return 0;
+}
+
+/**
+ * Halt the VFPU
+ */
+int Halt()
+{
+ assert(g_running);
+ // Tell the child to stop running the VHDL simulation
+ if (close(g_fpu_socket[1]) != 0)
+ return errno;
+ usleep(1000);
+ if (kill(g_fpu_pid, SIGKILL) != 0)
+ return errno;
+ g_running = false;
+ return 0;
+}
+
+float Exec(float opa, float opb, Opcode op, Rmode rmode)
+{
+ unsigned a; memcpy(&a, &opa, sizeof(float));
+ unsigned b; memcpy(&b, &opb, sizeof(float));
+
+ unsigned r = (unsigned)(Exec(Register(a), Register(b), op, rmode).to_ulong());
+ float result; memcpy(&result, &r, sizeof(float));
+ return result;
+}
+
+/**
+ * Tell the VFPU to execute an instruction, wait for it to finish, return the result
+ * TODO: Make this not mix C++ and C so badly?
+ * TODO: It will still only work for magic 32 bit FPU
+ */
+Register Exec(const Register & a, const Register & b, Opcode op, Rmode rmode)
+{
+ assert(g_running);
+
+ stringstream s;
+ s << hex << setw(8) << setfill('0') << a.to_ullong() << "\n" << b.to_ullong() << "\n" << setw(1) << op <<"\n" << setw(1) << rmode << "\n";
+ string str(s.str());
+ //Debug("Writing: %s", str.c_str());
+
+ // So we used C++ streams to make our C string...
+ assert(write(g_fpu_socket[1], str.c_str(), str.size()) == (int)str.size());
+
+ char buffer[BUFSIZ];
+ int len = read(g_fpu_socket[1], buffer, sizeof(buffer));
+ //assert(len == 9);
+ buffer[--len] = '\0'; // Get rid of newline
+ //Debug("Read: %s", buffer);
+
+ Register result(0);
+ for (int i = 0; i < len/2; ++i)
+ {
+ unsigned byte; // It is ONE byte (2 nibbles == 2 hex digits)
+ sscanf(buffer+2*i, "%02x", &byte);
+ result |= (byte << 8*(len/2-i-1));
+ }
+
+ stringstream s2;
+ s2 << hex << result.to_ullong();
+ //Debug("Result is: %s", s2.str().c_str());
+ return result;
+}
+
+}
+
+
--- /dev/null
+#ifndef _VFPU_H
+#define _VFPU_H
+
+/**
+ * Implements a terrible and hacky interface to use a virtual FPU to do floating point operations
+ */
+
+#include <bitset>
+
+namespace VFPU
+{
+ extern int Start(const char * vcd_output = NULL); // Starts the VFPU
+ extern int Halt(); // Halts the VFPU
+
+/**
+ -- 000 = add,
+ -- 001 = substract,
+ -- 010 = multiply,
+ -- 011 = divide,
+ -- 100 = square root
+ -- 101 = unused
+ -- 110 = unused
+ -- 111 = unused
+ */
+ typedef enum {ADD=0x000, SUB=0x001, MULT=0x010, DIV=0x011, SQRT=0x100} Opcode;
+ typedef enum {EVEN=0x00, ZERO=0x01, UP=0x10, DOWN=0x11} Rmode;
+ typedef std::bitset<32> Register;
+
+ extern Register Exec(const Register & a, const Register & b, Opcode op, Rmode rmode = EVEN); // operate with registers
+ extern float Exec(float a, float b, Opcode op, Rmode rmode = EVEN); //converts floats into registers and back
+}
+
+#endif //_VFPU_H
+
+
m_bounds.h *= scaleAmt;
}
+void View::DrawGrid()
+{
+ // Draw some grid lines at fixed pixel positions
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0.0, 1.0, 1.0, 0.0, -1.f, 1.f);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ glColor4f(0.9,0.9,0.9,0.1);
+ const float num_lines = 50.0;
+ for (float i = 0; i < num_lines; ++i)
+ {
+ glBegin(GL_LINES);
+ glVertex2f(i*(1.0/num_lines), 0.0);
+ glVertex2f(i*(1.0/num_lines), 1.0);
+ glEnd();
+ glBegin(GL_LINES);
+ glVertex2f(0.0,i*(1.0/num_lines));
+ glVertex2f(1.0,i*(1.0/num_lines));
+ glEnd();
+
+ }
+}
+
void View::Render()
{
static bool debug_output_done = false;
glClearColor(1.f,1.f,1.f,1.f);
glClear(GL_COLOR_BUFFER_BIT);
+ //DrawGrid(); // Draw the gridlines
+
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(Float(m_bounds.x), Float(m_bounds.x)+Float(m_bounds.w), Float(m_bounds.y) + Float(m_bounds.h), Float(m_bounds.y), -1.f, 1.f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
- glColor4f(0.f,0.f,0.f,1.f);
+ glColor4f(m_colour.r, m_colour.g, m_colour.b, m_colour.a);
glBegin(GL_QUADS);
for (unsigned id = 0; id < m_document.ObjectCount(); ++id)
{
}
glEnd();
+
for (unsigned id = 0; id < m_document.ObjectCount(); ++id)
{
if (m_document.m_objects.types[id] != RECT_OUTLINE)
class View
{
public:
- View(Document & document) : m_document(document), m_bounds(0,0,1,1) {}
+ View(Document & document, const Rect & bounds = Rect(0,0,1,1), const Colour & colour = Colour(0.f,0.f,0.f,1.f))
+ : m_document(document), m_bounds(bounds), m_colour(colour) {}
virtual ~View() {}
void Render();
void ScaleAroundPoint(Real x, Real y, Real scaleAmt);
private:
+ void DrawGrid();
Document & m_document;
Rect m_bounds;
+ Colour m_colour;
};
}