Don't write past the end of a GPU mem buffer.
[ipdf/code.git] / src / vfpu.cpp
1 #include "vfpu.h"
2 #include <stdlib.h>
3 #include <assert.h>
4 #include <errno.h>
5 #include <unistd.h>
6 #include <stdio.h>
7 #include <sys/types.h>
8 #include <sys/socket.h>
9 #include <sys/stat.h>
10 #include <sys/fcntl.h>
11 #include <stdbool.h>
12 #include <signal.h>
13 #include <string.h>
14
15 #include <sstream>
16 #include <iomanip>
17
18 #include "common.h"
19
20 using namespace std;
21
22 namespace VFPU
23 {
24         
25 static const char g_fpu[] = "vfpu";
26
27 static bool g_running = false;
28 static int g_fpu_socket[2] = {-1,-1};
29 static pid_t g_fpu_pid = -1;
30
31 /**
32  * Starts the VFPU
33  * @returns 0 on success, errno of the failing function on failure
34  */
35 int Start(const char * vcd_output)
36 {
37         assert(!g_running);
38         // create unix socket pair
39         
40         if (socketpair(AF_UNIX, SOCK_STREAM, 0, g_fpu_socket) != 0)
41                 return errno;
42         
43
44         g_fpu_pid = fork();
45         if (g_fpu_pid < 0) // error check
46                 return errno;
47
48
49         // Child branch
50         if (g_fpu_pid == 0)
51         {
52                 
53                 // Remap stdio to the socket
54                 dup2(g_fpu_socket[0],fileno(stdin));
55                 dup2(g_fpu_socket[0],fileno(stdout));
56                 
57                 // Unbuffer things; buffers are a pain
58                 setbuf(stdin, NULL); setbuf(stdout, NULL); setbuf(stderr, NULL);
59
60                 Debug("Child about to suppress stderr and exec vfpu");
61                 dup2(open("/dev/null", O_APPEND), fileno(stderr)); //LALALA I AM NOT LISTENING TO YOUR STUPID ERRORS GHDL
62                 if (vcd_output != NULL)
63                 {
64                         string s("--vcd=");
65                         s += vcd_output;
66                         execl(g_fpu, g_fpu, s.c_str(), NULL);
67                 }
68                 else    
69                 {
70                         execl(g_fpu, g_fpu,NULL);
71                 }
72                 int err = errno; // Because errno will be set again by the next system call
73                 Fatal("Uh oh! %s\n", strerror(err)); // We will never see this if something goes wrong... oh dear
74                 exit(err); // Child exits here.
75         }
76
77         // Parent branch
78         usleep(100);
79         g_running = true; // We are ready!
80         return 0;
81 }
82
83 /**
84  * Halt the VFPU
85  */
86 int Halt()
87 {
88         assert(g_running);
89         // Tell the child to stop running the VHDL simulation
90         if (close(g_fpu_socket[1]) != 0)
91                 return errno;
92         usleep(1000);
93         if (kill(g_fpu_pid, SIGKILL) != 0)
94                 return errno;
95         g_running = false;
96         return 0;
97 }
98
99 float Exec(float opa, float opb, Opcode op, Rmode rmode)
100 {
101         unsigned a; memcpy(&a, &opa, sizeof(float));
102         unsigned b; memcpy(&b, &opb, sizeof(float));
103         
104         unsigned r = (unsigned)(Exec(Register(a), Register(b), op, rmode).to_ulong());
105         float result; memcpy(&result, &r, sizeof(float));
106         return result;
107 }
108
109 /**
110  * Tell the VFPU to execute an instruction, wait for it to finish, return the result
111  * TODO: Make this not mix C++ and C so badly?
112  * TODO: It will still only work for magic 32 bit FPU
113  */
114 Register Exec(const Register & a, const Register &  b, Opcode op, Rmode rmode)
115 {
116         assert(g_running);
117         stringstream s;
118         s << hex << setw(8) << setfill('0') << a.to_ulong() << "\n" << b.to_ulong() << "\n" << setw(1) << op <<"\n" << setw(1) << rmode << "\n";
119         string str(s.str());
120         //Debug("Writing: %s", str.c_str());
121
122         // So we used C++ streams to make our C string...
123         assert(write(g_fpu_socket[1], str.c_str(), str.size()) == (int)str.size());
124
125         char buffer[BUFSIZ]; 
126         int len = read(g_fpu_socket[1], buffer, sizeof(buffer));
127         //assert(len == 9);
128         buffer[--len] = '\0'; // Get rid of newline
129         //Debug("Read: %s", buffer);
130         
131         Register result(0);
132         for (int i = 0; i < len/2; ++i)
133         {
134                 unsigned byte; // It is ONE byte (2 nibbles == 2 hex digits)
135                 sscanf(buffer+2*i, "%02x", &byte);
136                 result |= (byte << 8*(len/2-i-1));
137         }
138         
139         stringstream s2;
140         //TODO: Make it compile on non C++11
141         s2 << hex << result.to_ulong();
142         //Debug("Result is: %s", s2.str().c_str());
143         return result;
144 }
145
146 }
147
148

UCC git Repository :: git.ucc.asn.au