From 2c9191c4b365e08bf3ee4272a190473a7c372ca1 Mon Sep 17 00:00:00 2001
From: NIIBE Yutaka <gniibe@fsij.org>
Date: Fri, 8 Sep 2017 20:44:56 +0900
Subject: Implement flash ROM emulation on GNU/LInux.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
---
 mcu/sys-gnu-linux.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 119 insertions(+), 2 deletions(-)

(limited to 'mcu')

diff --git a/mcu/sys-gnu-linux.c b/mcu/sys-gnu-linux.c
index f7f51b0..b6e88c3 100644
--- a/mcu/sys-gnu-linux.c
+++ b/mcu/sys-gnu-linux.c
@@ -1,6 +1,15 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include <stdio.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
 #include "board.h"
 
 const uint8_t sys_version[8] = {
@@ -19,36 +28,144 @@ set_led (int on)
   puts (on ? "*": "");
 }
 
+static const char *flash_path;
+static size_t flash_size;
+static void * flash_addr;
+static int flash_fd;
+
+void
+flash_init (const char *f_name)
+{
+  int fd;
+  struct stat sb;
+  void *addr;
+
+  fd = open (f_name, O_RDONLY);
+  if (fd < 0)
+    {
+      perror ("flash_init: open");
+      exit (1);
+    }
+
+  if (fstat (fd, &sb) < 0)
+    {
+      perror ("flash_init: fstat");
+      exit (1);
+    }
+
+  addr = mmap (NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
+  if (addr == MAP_FAILED)
+    {
+      perror ("flash_init: mmap");
+      exit (1);
+    }
+
+  if (close (fd) < 0)
+    {
+      perror ("flash_init: close");
+      exit (1);
+    }
+
+  flash_path = f_name;
+  flash_addr = addr;
+  flash_size = sb.st_size;
+}
+
 void
 flash_unlock (void)
 {
+  int fd;
+
+  fd = open (flash_path, O_WRONLY);
+  if (fd < 0)
+    {
+      perror ("flash_unlock: open");
+      exit (1);
+    }
+  flash_fd = fd;
 }
 
 int
 flash_program_halfword (uint32_t addr, uint16_t data)
 {
+  off_t offset;
+  char buf[2];
+
   fprintf (stderr, "flash_program_halfword: addr=%08x, data=%04x\n", addr, data);
+  offset = (off_t)(addr - (uint32_t)flash_addr);
+  offset = lseek (flash_fd, offset, SEEK_SET);
+  if (offset == (off_t)-1)
+    {
+      perror ("flash_program_halfword");
+      return 1;
+    }
+  buf[0] = (data & 0xff);
+  buf[1] = (data >> 8);
+  if (write (flash_fd, buf, 2) != 2)
+    {
+      perror ("flash_program_halfword");
+      return 2;
+    }
   return 0;
 }
 
+static const uint8_t erased[] = { [0 ... 1023 ] = 0xff };
+
 int
 flash_erase_page (uint32_t addr)
 {
+  off_t offset;
+
   fprintf (stderr, "flash_erase_page: addr=%08x\n", addr);
+
+  offset = (off_t)(addr - (uint32_t)flash_addr);
+  offset = lseek (flash_fd, offset, SEEK_SET);
+  if (offset == (off_t)-1)
+    {
+      perror ("flash_erase_page");
+      return 1;
+    }
+
+  if (write (flash_fd, erased, sizeof (erased)) != len)
+    {
+      perror ("flash_erase_page");
+      return 2;
+    }
   return 0;
 }
 
 int
 flash_check_blank (const uint8_t *p_start, size_t size)
 {
-  fprintf (stderr, "flash_check_blank: addr=%p, size=%zd\n", p_start, size);
-  return 0;
+  const uint8_t *p;
+
+  for (p = p_start; p < p_start + size; p++)
+    if (*p != 0xff)
+      return 0;
+
+  return 1;
 }
 
 int
 flash_write (uint32_t dst_addr, const uint8_t *src, size_t len)
 {
+  off_t offset;
+
   fprintf (stderr, "flash_write: addr=%08x, %p, %zd\n", dst_addr, src, len);
+
+  offset = (off_t)(dst_addr - (uint32_t)flash_addr);
+  offset = lseek (flash_fd, offset, SEEK_SET);
+  if (offset == (off_t)-1)
+    {
+      perror ("flash_write");
+      return 1;
+    }
+
+  if (write (flash_fd, src, len) != len)
+    {
+      perror ("flash_write");
+      return 2;
+    }
   return 0;
 }
 
-- 
cgit v1.2.3