An interface for a FPU compiled from VHDL
[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 namespace VFPU
16 {
17
18 static const char g_fpu[] = "../vhdl/tb_fpu";
19
20 static bool g_running = false;
21 static int g_fpu_socket[2] = {-1,-1};
22 static pid_t g_fpu_pid = -1;
23
24 /**
25  * Starts the VFPU
26  * @returns 0 on success, errno of the failing function on failure
27  */
28 int Start()
29 {
30         assert(!g_running);
31         // create unix socket pair
32         
33         if (socketpair(AF_UNIX, SOCK_STREAM, 0, g_fpu_socket) != 0)
34                 return errno;
35         
36
37         g_fpu_pid = fork();
38         if (g_fpu_pid < 0) // error check
39                 return errno;
40
41
42         // Child branch
43         if (g_fpu_pid == 0)
44         {
45                 
46                 // Remap stdio to the socket
47                 dup2(g_fpu_socket[0],fileno(stdin));
48                 dup2(g_fpu_socket[0],fileno(stdout));
49                 dup2(open("/dev/null", O_APPEND), fileno(stderr)); //LALALA I AM NOT LISTENING TO YOUR STUPID ERRORS GHDL
50                 
51                 // Unbuffer things; buffers are a pain
52                 setbuf(stdin, NULL); setbuf(stdout, NULL); setbuf(stderr, NULL);
53
54                 //fprintf(stderr, "Goodbye!\n");
55                 execl(g_fpu, g_fpu,NULL);
56                 fprintf(stderr, "Uh oh! %s\n", strerror(errno)); // We will never see this if something goes wrong... oh dear
57                 exit(errno); // Child exits here.
58         }
59
60         // Parent branch
61         usleep(100);
62         g_running = true; // We are ready!
63         return 0;
64 }
65
66 /**
67  * Halt the VFPU
68  */
69 int Halt()
70 {
71         assert(g_running);
72         // Tell the child to stop running the VHDL simulation
73         if (close(g_fpu_socket[1]) != 0)
74                 return errno;
75         usleep(1000);
76         if (kill(g_fpu_pid, SIGKILL) != 0)
77                 return errno;
78         g_running = false;
79         return 0;
80 }
81
82 /**
83  * Tell the VFPU to execute an instruction, wait for it to finish, return the result
84  * TODO: Generalise for non 32bit Registers
85  */
86 Register Exec(const Register & opa, const Register &  opb, Opcode op)
87 {
88         assert(g_running);
89         
90         // Copy floats into 32 bits (casting will alter the representation) 
91         unsigned a; memcpy(&a, &opa, 8);
92         unsigned b; memcpy(&b, &opb, 8);
93
94         
95         char buffer[BUFSIZ];
96         int len = sprintf(buffer, "%08x\n%08x\n%03x\n",a, b, op);  // This is... truly awful... why am I doing this
97         //fprintf(stderr, "Writing:\n%s", buffer);
98
99         assert(len == 9+9+4); 
100         assert(write(g_fpu_socket[1], buffer, len) == len);
101         //fprintf(stderr, "Wrote!\n");
102
103         len = read(g_fpu_socket[1], buffer, sizeof(buffer));
104         assert(len == 9);
105         buffer[len] = '\0';
106         
107         
108         unsigned result = 0x00000000;
109         for (int i = 0; i < len/2; ++i)
110         {
111                 unsigned byte2; // cos its two bytes
112                 sscanf(buffer+2*i, "%02x", &byte2);
113                 result |= (byte2 << 8*(len/2-i-1));
114         }
115         
116         //fprintf(stderr, "Buffer: %s\nResult: %08x\n", buffer, result);
117         
118         Register r;
119         memcpy(&r, &result, 8); // Amazing.
120         return r;
121 }
122
123 }
124
125

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