]> rtime.felk.cvut.cz Git - mf6xx.git/commitdiff
Most of the card logic is implemented. Socket doesn't work. Not tested.
authorRostislav Lisovy <lisovy@gmail.com>
Sun, 3 Apr 2011 18:47:43 +0000 (20:47 +0200)
committerRostislav Lisovy <lisovy@gmail.com>
Sun, 3 Apr 2011 18:47:43 +0000 (20:47 +0200)
src/qemu/hw/mf624.c

index d4a0aa4883286fffdd12b0f96d0556d5de1c7506..a4208ea5f1fa1723f9858e5db764d37c943917da 100755 (executable)
@@ -6,20 +6,29 @@
  */
 #include "hw.h"
 #include "pci.h"
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h> 
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
 
 #define PCI_VENDOR_ID_HUMUSOFT         0x186c
 #define PCI_DEVICE_ID_MF624            0x0624
-
 #define PCI_CLASS_SIGNAL_PROCESSING_CONTROLLER         0x1180
 
-/* --- Hardware specific --- */
+
+#define BAR0_size                      32
+#define BAR2_size                      128
+#define BAR4_size                      128
+
 /* BAR0 */
 #define INTCSR_off                     0x4C
 #define GPIOC_off                      0x54
 
 /* BAR2 */ 
 #define ADDATA_off                     0x00
-#define ADCTRL_off                     ADDATA_off
+#define ADCTRL_off                     0x00
 #define ADDATA1_off                    0x02
 #define ADDATA2_off                    0x04
 #define ADDATA3_off                    0x06
@@ -28,9 +37,9 @@
 #define ADDATA6_off                    0x0C
 #define ADDATA7_off                    0x0E
 #define DOUT_off                       0x10
-#define DIN_off                                DOUT_off
+#define DIN_off                                0x10
 #define ADSTART_off                    0x20
-#define DA0_off                                ADSTART_off
+#define DA0_off                                0x20
 #define DA1_off                                0x22
 #define DA2_off                                0x24
 #define DA3_off                                0x26
@@ -39,6 +48,9 @@
 #define DA6_off                                0x2C
 #define DA7_off                                0x2E
 
+#define GPIOC_EOLC_mask                        (1 << 17)
+#define GPIOC_LDAC_mask                        (1 << 23)
+#define GPIOC_DACEN_mask               (1 << 26)
 
 
 typedef struct {
@@ -48,29 +60,48 @@ typedef struct {
 
 typedef struct {
        uint16_t ADDATA;
-       #define ADCTRL ADDATA
+       uint16_t ADCTRL;
        uint16_t ADDATA1;
-       // ...
+       uint16_t ADDATA2;
+       uint16_t ADDATA3;
+       uint16_t ADDATA4;
+       uint16_t ADDATA5;
+       uint16_t ADDATA6;
+       uint16_t ADDATA7;
        uint16_t DIN;
-       #define DOUT DIN
-       // ...
+       uint16_t DOUT;
+       uint16_t DA0;
+       uint16_t DA1;
+       uint16_t DA2;
+       uint16_t DA3;
+       uint16_t DA4;
+       uint16_t DA5;
+       uint16_t DA6;
+       uint16_t DA7;
 } BAR2_t;
 
 typedef struct {
-       uint32_t CTR0STATUS;
-       #define CTR0MODE CTR0STATUS;
-       uint32_t CTR0;
-       #define CTR0A CTR0
-       // ....
+//     uint32_t CTR0STATUS;
+//     uint32_t CTR0MODE;
+//     uint32_t CTR0;
+//     uint32_t CTR0A;
+//     ...
 } BAR4_t;
 
 typedef struct {
        PCIDevice dev;
 
+       int socket_srv;
+       int socket_tmp;
+
+       uint16_t real_world_AD[8]; /* The real voltage which is on inputs od A/D convertors.
+                                       Until new conversion is started, there is old value in 
+                                       ADC registers*/ 
+
        // for cpu_register_physical_memory() function
-       unsigned int BAR0_offset;
-       unsigned int BAR2_offset;
-       unsigned int BAR4_offset;
+       unsigned int BAR0_mem_table_index;
+       unsigned int BAR2_mem_table_index;
+       unsigned int BAR4_mem_table_index;
        
        // Internal registers values
        BAR0_t BAR0;
@@ -78,18 +109,134 @@ typedef struct {
        BAR4_t BAR4;
 } mf624_state_t;
 
+//-----------------------------------------------------------------------------
+void mf624_init_registers(mf624_state_t* s)
+{
+#define INTCSR_default_value           0x000300
+#define GPIOC_default_value            0x006C0 | (0x10 << 21) | (2 << 25)
+
+       //Initialize all registers to default values
+       s->BAR0.INTCSR = INTCSR_default_value;
+       s->BAR0.GPIOC = GPIOC_default_value; 
+       s->BAR2.ADDATA = 0x0;
+       s->BAR2.ADCTRL = 0x0;
+       s->BAR2.ADDATA1 = 0x0;
+       s->BAR2.ADDATA2 = 0x0;
+       s->BAR2.ADDATA3 = 0x0;
+       s->BAR2.ADDATA4 = 0x0;
+       s->BAR2.ADDATA5 = 0x0;
+       s->BAR2.ADDATA6 = 0x0;
+       s->BAR2.ADDATA7 = 0x0;
+
+       s->BAR2.DIN = 0xFF;
+       s->BAR2.DOUT = 0x00;
+       s->BAR2.DA0 = 0x3FFF;
+       s->BAR2.DA1 = 0x3FFF;
+       s->BAR2.DA2 = 0x3FFF;
+       s->BAR2.DA3 = 0x3FFF;
+       s->BAR2.DA4 = 0x3FFF;
+       s->BAR2.DA5 = 0x3FFF;
+       s->BAR2.DA6 = 0x3FFF;
+       s->BAR2.DA7 = 0x3FFF;
+
+}
+
+
+void socket_write(const char* reg, unsigned int val)
+{
+       printf("%s=%x\n", reg, val);    
 
+}
+
+void init_socket(mf624_state_t* dev)
+{
+       struct sockaddr_in addr_srv;
+       struct sockaddr_in addr_client;
+       int port = 55555;
+       int yes = 1;
+
+       dev->socket_srv = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+       if (dev->socket_srv == -1) {
+               perror("socket()");
+               return;
+       }
+       
+       if (setsockopt(dev->socket_srv, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
+               perror("setsockopt()");
+               return;
+       }
+
+
+       socklen_t len = sizeof(addr_srv);
+       memset(&addr_srv, 0, len);
+       addr_srv.sin_family = AF_INET;
+       addr_srv.sin_addr.s_addr = htonl(INADDR_ANY);
+       addr_srv.sin_port = htons(port);
+       if(bind(dev->socket_srv, (struct sockaddr*) &addr_srv, len) == -1) {
+               perror("bind()");
+               return;
+       }
+       
+       if (listen(dev->socket_srv, 5) == -1) {
+               perror("listen()");
+               return;
+       }
+
+       while(1) {
+               socklen_t len_client = sizeof(addr_client);
+               dev->socket_tmp = accept(dev->socket_srv, (struct sockaddr*) &addr_client, &len_client);
+               if (dev->socket_tmp == -1) {
+                       perror("accept()");
+                       continue;
+               }
+               //open(dev, );
+               //close(dev->socket_tmp);
+       }
+}
+
+//-----------------------------------------------------------------------------
 
 void mf624_BAR0_write32(void *opaque, target_phys_addr_t addr, uint32_t value)
 {
        mf624_state_t *s = opaque;
 
-       switch (addr) {
+       switch (addr % BAR0_size) {
                case INTCSR_off:
-                       s->BAR0.INTCSR = value;
+                       s->BAR0.INTCSR = (value & 0x7FF) | INTCSR_default_value; // Only first 11 bits are writable
+                       socket_write("INTCSR", s->BAR0.INTCSR);
                        break;
                case GPIOC_off:
-                       s->BAR0.GPIOC = value;
+                       //Don't write anywhere else than into these two bits
+                       s->BAR0.GPIOC = (value & (GPIOC_LDAC_mask | GPIOC_DACEN_mask)) | GPIOC_default_value;
+                       socket_write("GPIOC", s->BAR0.GPIOC);
+
+                       //Is DAC enabled & Output enabled?
+                       if (!(s->BAR0.GPIOC & GPIOC_LDAC_mask) &&
+                               (s->BAR0.GPIOC & GPIOC_DACEN_mask)) {
+                               socket_write("DA0", s->BAR2.DA0);
+                               socket_write("DA1", s->BAR2.DA1);
+                               socket_write("DA2", s->BAR2.DA2);
+                               socket_write("DA3", s->BAR2.DA3);
+                               socket_write("DA4", s->BAR2.DA4);
+                               socket_write("DA5", s->BAR2.DA5);
+                               socket_write("DA6", s->BAR2.DA6);
+                               socket_write("DA7", s->BAR2.DA7);
+                       }
+                       
+                       //Is output forced to GND?
+                       if (!(s->BAR0.GPIOC & GPIOC_DACEN_mask))
+                       {
+                               #define GND     0
+                               socket_write("DA0", GND);
+                               socket_write("DA1", GND);
+                               socket_write("DA2", GND);
+                               socket_write("DA3", GND);
+                               socket_write("DA4", GND);
+                               socket_write("DA5", GND);
+                               socket_write("DA6", GND);
+                               socket_write("DA7", GND);
+                       }
+                               
                        break;
                default:
                        printf("mf624_BAR0_write32(): addr = %d; value = %d\n", addr, value);
@@ -97,11 +244,12 @@ void mf624_BAR0_write32(void *opaque, target_phys_addr_t addr, uint32_t value)
        }
 }
 
+
 uint32_t mf624_BAR0_read32(void *opaque, target_phys_addr_t addr)
 {
        mf624_state_t *s = opaque;
 
-       switch (addr) {
+       switch (addr % BAR0_size) {
                case INTCSR_off:
                        return s->BAR0.INTCSR;
                case GPIOC_off:
@@ -115,17 +263,80 @@ uint32_t mf624_BAR0_read32(void *opaque, target_phys_addr_t addr)
 
 uint32_t mf624_BAR2_read16(void *opaque, target_phys_addr_t addr)
 {
-       printf("mf624_BAR2_read16(): addr = %d\n", addr);
-       return 0x0;
+       int i;
+       mf624_state_t *s = opaque;
+
+       switch (addr % BAR2_size) {
+               case ADDATA_off:
+                       return s->BAR2.ADDATA; //FIXME Madness? This ... is ... FIFO!
+
+               case ADDATA1_off:
+                       if (!(s->BAR0.GPIOC & GPIOC_EOLC_mask)) { //Has the conversion already ended?
+                               return s->BAR2.ADDATA1;
+                       }
+                       return 0xFFFF; // Semirandom value
+
+               case ADDATA2_off:
+                       if (!(s->BAR0.GPIOC & GPIOC_EOLC_mask)) { //Has the conversion already ended?
+                               return s->BAR2.ADDATA2;
+                       }
+                       return 0xFFFF; // Semirandom value
+
+               case DIN_off:
+                       return s->BAR2.DIN;
+
+               /* A/D Conversion Start. Reading this register triggers A/D
+               conversion for all channels selected in ADCTRL. */
+               case ADSTART_off:
+                       s->BAR0.GPIOC |= GPIOC_EOLC_mask; // Conversion in progress
+                       for (i = 0; i < 500000; i++) 
+                               ; // Small delay simulating real conversion
+
+                       // Check before assignement, if particular ADC is enabled
+                       s->BAR2.ADDATA  = (s->BAR2.ADCTRL & (1 << 0)) ? s->real_world_AD[0] : s->BAR2.ADDATA;
+                       s->BAR2.ADDATA1 = (s->BAR2.ADCTRL & (1 << 1)) ? s->real_world_AD[1] : s->BAR2.ADDATA1;
+                       s->BAR2.ADDATA2 = (s->BAR2.ADCTRL & (1 << 2)) ? s->real_world_AD[2] : s->BAR2.ADDATA2;
+                       s->BAR2.ADDATA3 = (s->BAR2.ADCTRL & (1 << 3)) ? s->real_world_AD[3] : s->BAR2.ADDATA3;
+                       s->BAR2.ADDATA4 = (s->BAR2.ADCTRL & (1 << 4)) ? s->real_world_AD[4] : s->BAR2.ADDATA4;
+                       s->BAR2.ADDATA5 = (s->BAR2.ADCTRL & (1 << 5)) ? s->real_world_AD[5] : s->BAR2.ADDATA5;
+                       s->BAR2.ADDATA6 = (s->BAR2.ADCTRL & (1 << 6)) ? s->real_world_AD[6] : s->BAR2.ADDATA6;
+                       s->BAR2.ADDATA7 = (s->BAR2.ADCTRL & (1 << 7)) ? s->real_world_AD[7] : s->BAR2.ADDATA7;
+                       
+                       return 0xFFFF; // Semirandom value
+               default:
+                       printf("mf624_BAR2_read16(): addr = %d\n", addr);
+                       return 0x0;
+       }
 }
 
+
 void mf624_BAR2_write16(void *opaque, target_phys_addr_t addr, uint32_t value)
 {
        mf624_state_t *s = opaque;
 
-       switch (addr - 128) {
+       switch (addr % BAR2_size) {
+               case ADCTRL_off:
+                       s->BAR2.ADCTRL = value;
+                       socket_write("ADCTRL", s->BAR2.ADCTRL);
+                       break;
                case DOUT_off:
                        s->BAR2.DOUT = value;
+                       socket_write("DOUT", s->BAR2.DOUT);
+                       break;
+               case DA0_off:
+                       s->BAR2.DA0 = value;
+                       //Is DAC enabled & Output enabled?
+                       if (!(s->BAR0.GPIOC & GPIOC_LDAC_mask) &&
+                               (s->BAR0.GPIOC & GPIOC_DACEN_mask)) {
+                               socket_write("DA0", s->BAR2.DA0);
+                       }
+                       break;
+               case DA1_off:
+                       s->BAR2.DA1 = value;
+                       if (!(s->BAR0.GPIOC & GPIOC_LDAC_mask) && 
+                               (s->BAR0.GPIOC & GPIOC_DACEN_mask)) {
+                               socket_write("DA1", s->BAR2.DA1);
+                       }
                        break;
                default:
                        printf("mf624_BAR2_write16(): addr = %d; value = %d\n", addr, value);
@@ -134,6 +345,7 @@ void mf624_BAR2_write16(void *opaque, target_phys_addr_t addr, uint32_t value)
 
 }
 
+
 void mf624_BAR4_write32(void *opaque, target_phys_addr_t addr, uint32_t value)
 {
        printf("mf624_BAR4_write32(): addr = %d; value = %d\n", addr, value);
@@ -190,16 +402,16 @@ static void mf624_map(PCIDevice *pci_dev, int region_num,
 
        switch (region_num) {
                case 0:
-                       printf("reg%d, addr = %x\n", region_num, addr);
-                       cpu_register_physical_memory(addr + 0x0, 32, s->BAR0_offset);
+                       //printf("reg%d, addr = %x\n", region_num, addr);
+                       cpu_register_physical_memory(addr + 0x0, BAR0_size, s->BAR0_mem_table_index);
                        break;
                case 2:
-                       printf("reg%d, addr = %x\n", region_num, addr);
-                       cpu_register_physical_memory(addr + 0x0, 128, s->BAR2_offset);
+                       //printf("reg%d, addr = %x\n", region_num, addr);
+                       cpu_register_physical_memory(addr + 0x0, BAR2_size, s->BAR2_mem_table_index);
                        break;
                case 4:
-                       printf("reg%d, addr = %x\n", region_num, addr);
-                       cpu_register_physical_memory(addr + 0x0, 128, s->BAR4_offset);
+                       //printf("reg%d, addr = %x\n", region_num, addr);
+                       cpu_register_physical_memory(addr + 0x0, BAR4_size, s->BAR4_mem_table_index);
                        break;
                default:
                        printf("FFFUUU\n");
@@ -212,6 +424,8 @@ static int pci_mf624_init(PCIDevice *pci_dev)
        mf624_state_t *s = DO_UPCAST(mf624_state_t, dev, pci_dev); //alocation of mf624_state_t
        uint8_t *pci_conf;
 
+       mf624_init_registers(s);
+
        pci_conf = s->dev.config;
        pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_HUMUSOFT);
        pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_MF624);
@@ -225,34 +439,38 @@ static int pci_mf624_init(PCIDevice *pci_dev)
 
 
        // return value of cpu_register_io_memory is IO INDEX
-       s->BAR0_offset = cpu_register_io_memory(mf624_BAR0_read,
-                                        mf624_BAR0_write,
-                                        s,
-                                        DEVICE_NATIVE_ENDIAN);
+       s->BAR0_mem_table_index = cpu_register_io_memory(mf624_BAR0_read,
+                                                mf624_BAR0_write,
+                                                s,
+                                                DEVICE_NATIVE_ENDIAN);
 
-       s->BAR2_offset = cpu_register_io_memory(mf624_BAR2_read,
-                                        mf624_BAR2_write,
-                                        s,
-                                        DEVICE_NATIVE_ENDIAN);
+       s->BAR2_mem_table_index = cpu_register_io_memory(mf624_BAR2_read,
+                                                mf624_BAR2_write,
+                                                s,
+                                                DEVICE_NATIVE_ENDIAN);
 
-       s->BAR4_offset = cpu_register_io_memory(mf624_BAR4_read,
-                                        mf624_BAR4_write,
-                                        s,
-                                        DEVICE_NATIVE_ENDIAN);
+       s->BAR4_mem_table_index = cpu_register_io_memory(mf624_BAR4_read,
+                                                mf624_BAR4_write,
+                                                s,
+                                                DEVICE_NATIVE_ENDIAN);
 
        //printf("BAR0: %d\n", s->BAR0_offset);
        //printf("BAR2: %d\n", s->BAR2_offset);
        //printf("BAR4: %d\n", s->BAR4_offset);
 
-       pci_register_bar(&s->dev, 0, 32, PCI_BASE_ADDRESS_SPACE_MEMORY, mf624_map);
-       pci_register_bar(&s->dev, 2, 128, PCI_BASE_ADDRESS_SPACE_MEMORY, mf624_map);
-       pci_register_bar(&s->dev, 4, 128, PCI_BASE_ADDRESS_SPACE_MEMORY, mf624_map);
+       pci_register_bar(&s->dev, 0, BAR0_size, PCI_BASE_ADDRESS_SPACE_MEMORY, mf624_map);
+       pci_register_bar(&s->dev, 2, BAR2_size, PCI_BASE_ADDRESS_SPACE_MEMORY, mf624_map);
+       pci_register_bar(&s->dev, 4, BAR4_size, PCI_BASE_ADDRESS_SPACE_MEMORY, mf624_map);
 
+       //init_socket(s);
        return 0;
 }
 
 static int pci_mf624_exit(PCIDevice *pci_dev)
 {
+       mf624_state_t *s = DO_UPCAST(mf624_state_t, dev, pci_dev);
+       close(s->socket_srv);
+
        return 0;
 }