summaryrefslogtreecommitdiffstats
path: root/sw/programmer
diff options
context:
space:
mode:
authorNao Pross <naopross@thearcway.org>2017-08-07 19:27:05 +0200
committerNao Pross <naopross@thearcway.org>2017-08-07 19:27:05 +0200
commitd0801b36b47d8f3da610597160fde92059fd7e62 (patch)
treef9f0e348145c3548433e60adbf459e784b909f96 /sw/programmer
parentfilesystem structure intro and docs (diff)
downloadz80uPC-d0801b36b47d8f3da610597160fde92059fd7e62.tar.gz
z80uPC-d0801b36b47d8f3da610597160fde92059fd7e62.zip
implementation for avr programmer
the programmer will receive the binary in blocks of defined size by a program under sw/programmer/linux (moved from sw/linux).
Diffstat (limited to 'sw/programmer')
-rw-r--r--sw/programmer/avr/fileinfo.h13
-rw-r--r--sw/programmer/avr/main.c109
-rw-r--r--sw/programmer/avr/makefile31
-rw-r--r--sw/programmer/avr/usart.c107
-rw-r--r--sw/programmer/avr/usart.h96
-rw-r--r--sw/programmer/linux/config.h26
-rw-r--r--sw/programmer/linux/configure.ac23
-rw-r--r--sw/programmer/linux/makefile.am2
-rw-r--r--sw/programmer/linux/reading_links.txt4
-rw-r--r--sw/programmer/linux/src/main.c13
-rw-r--r--sw/programmer/linux/src/makefile.am7
-rw-r--r--sw/programmer/linux/src/serial.c42
-rw-r--r--sw/programmer/linux/src/serial.h17
-rw-r--r--sw/programmer/linux/src/ui.c90
-rw-r--r--sw/programmer/linux/src/ui.h17
-rwxr-xr-xsw/programmer/linux/src/z80progbin0 -> 34688 bytes
-rw-r--r--sw/programmer/linux/src/z80prog.ui222
17 files changed, 819 insertions, 0 deletions
diff --git a/sw/programmer/avr/fileinfo.h b/sw/programmer/avr/fileinfo.h
new file mode 100644
index 0000000..6c831ed
--- /dev/null
+++ b/sw/programmer/avr/fileinfo.h
@@ -0,0 +1,13 @@
+#ifndef __FILEINFO_H__
+#define __FILEINFO_H__
+
+#include <stdio.h>
+
+struct file_info
+{
+ size_t size;
+ size_t blklen;
+ uint16_t start_addr;
+};
+
+#endif
diff --git a/sw/programmer/avr/main.c b/sw/programmer/avr/main.c
new file mode 100644
index 0000000..90d05fa
--- /dev/null
+++ b/sw/programmer/avr/main.c
@@ -0,0 +1,109 @@
+#include "fileinfo.h"
+#include "usart.h"
+#include <util/delay.h>
+
+#define EEPROM_TICK_MS 10
+
+#define ADDRCR PORTB
+#define EEPROMCR PORTC
+#define EEPROMDR PORTD
+
+#define ADDR_BIT 0
+#define ADDR_EL 3
+#define ADDR_EH 4
+#define ADDR_DL 5
+#define ADDR_DH 6
+
+#define EEPROM_WR 0
+#define EEPROM_RD 1
+#define EEPROM_CLK 2
+
+
+void eeprom_write(uint16_t addr, uint8_t byte);
+void eeprom_tick();
+
+int main(void)
+{
+ uint8_t *buffer, i;
+ uint16_t addr;
+ size_t read;
+
+ struct file_info *finfo = malloc(sizeof(struct file_info));
+
+ DDRB = 0x7F;
+ DDRC = 0x83;
+ DDRD = 0xFC;
+
+ /* get configuration */
+ usart_init(1200);
+
+ usart_print("EEPROM Programmer\n\r");
+
+ do {
+ usart_print("Waiting for configuration\n\r");
+ read = usart_read((uint8_t *) finfo, sizeof(struct file_info));
+ } while (read != sizeof(struct file_info));
+
+ usart_print("Programmer Ready\n<waiting for binary>\n\r");
+
+ buffer = malloc(finfo->blklen);
+ addr = finfo->start_addr;
+
+ /* read file */
+ while ((read = usart_read(buffer, finfo->blklen))) {
+ for (i = 0; i < read; i++) {
+ eeprom_write(addr + i, *(buffer++));
+ }
+
+ addr += finfo->blklen;
+ }
+
+ return 0;
+}
+
+
+void eeprom_write(uint16_t addr, uint8_t byte)
+{
+ int bit;
+
+ /* set address */
+ for (bit = 0; bit < 8; bit++) {
+ // clear bit
+ ADDRCR &= ~0x07;
+ // select the bit
+ ADDRCR |= bit;
+
+ // write bit for lower byte
+ if (addr & _BV(bit))
+ ADDRCR |= _BV(ADDR_DL);
+ else
+ ADDRCR &= ~_BV(ADDR_DL);
+
+ // write bit for higher byte
+ if ((addr>>8) & _BV(bit))
+ ADDRCR |= _BV(ADDR_DH);
+ else
+ ADDRCR &= ~_BV(ADDR_DH);
+ }
+
+ /* set data */
+ EEPROMDR = byte;
+ EEPROMCR &= ~(_BV(ADDR_EH) | _BV(ADDR_EL));
+
+ /* write eeprom */
+ EEPROMCR &= ~_BV(EEPROM_WR);
+ eeprom_tick();
+
+ EEPROMCR |= _BV(EEPROM_WR);
+ EEPROMCR |= _BV(ADDR_EH) | _BV(ADDR_EL);
+}
+
+/* pulse the clock line for the eeprom */
+void eeprom_tick()
+{
+ EEPROMCR |= _BV(EEPROM_CLK);
+ _delay_ms(EEPROM_TICK_MS);
+ EEPROMCR &= ~_BV(EEPROM_CLK);
+ _delay_ms(EEPROM_TICK_MS);
+}
+
diff --git a/sw/programmer/avr/makefile b/sw/programmer/avr/makefile
new file mode 100644
index 0000000..95fb5fe
--- /dev/null
+++ b/sw/programmer/avr/makefile
@@ -0,0 +1,31 @@
+###
+# Project settings
+#
+TARGET := programmer
+SOURCES := $(wildcard *.c)
+
+###
+# Compiler settings
+#
+CC := avr-gcc
+PORT := /dev/ttyUSB0
+MCU := atmega328p
+
+CFLAGS := -g -Wall -mcall-prologues -mmcu=$(MCU) -Os -I . \
+ -DF_CPU=1000000UL
+LDFLAGS := -Wl,-gc-sections -Wl,-relax
+
+.PHONY: all clean program
+all: $(TARGET).hex
+
+clean:
+ rm -f *.o *.hex *.obj *.bin
+
+$(TARGET).hex: $(TARGET).bin
+ avr-objcopy -R .eeprom -O ihex $(TARGET).bin $@
+
+$(TARGET).bin: $(SOURCES)
+ $(CC) $(CFLAGS) $(SOURCES) -o $@ $(LDFLAGS)
+
+program: $(TARGET).hex
+ avrdude -p $(MCU) -c usbasp -P usb -U flash:w:$(TARGET).hex
diff --git a/sw/programmer/avr/usart.c b/sw/programmer/avr/usart.c
new file mode 100644
index 0000000..8c2eb38
--- /dev/null
+++ b/sw/programmer/avr/usart.c
@@ -0,0 +1,107 @@
+#include "usart.h"
+
+static uint16_t usart_baudrate;
+static uint16_t usart_baud_prescale;
+
+void usart_init(uint16_t baudrate)
+{
+ // enable RX and TX
+ UCSR0B |= _BV(RXEN0) | _BV(TXEN0);
+
+ // set 8 bit size char
+ UCSR0C |= _BV(UCSZ01) | _BV(UCSZ00);
+
+ // set baudrate
+ usart_baudrate = baudrate;
+ usart_baud_prescale = (F_CPU / (usart_baudrate * 16)) -1;
+
+ UBRR0L = usart_baud_prescale;
+ UBRR0H = usart_baud_prescale >> 8;
+}
+
+void usart_send_byte(uint8_t data)
+{
+ while (!(UCSR0A & _BV(UDRE0)));
+ UDR0 = data;
+}
+
+void usart_send(uint8_t *data, size_t len)
+{
+ uint8_t *p = data;
+
+ while (len--) {
+ usart_send_byte(*(p++));
+ }
+}
+
+void usart_print(char *str)
+{
+ char *p = str;
+ size_t len = 0;
+
+ while (*p++ != '\0') {
+ len++;
+ }
+
+ usart_send((uint8_t *) str, len);
+}
+
+int usart_read_byte(uint8_t *byte)
+{
+ uint16_t timeout = USART_TIMEOUT;
+
+ do {
+ if (UCSR0A & _BV(RXC0)) {
+ *byte = UDR0;
+ return 0;
+ }
+ } while (timeout--);
+
+ return -1;
+}
+
+uint8_t usart_read_byte_nt(void)
+{
+ while ((UCSR0A & _BV(RXC0)) == 0);
+ return UDR0;
+}
+
+
+size_t usart_read(uint8_t *buffer, size_t len)
+{
+ size_t read = 0;
+ uint8_t *p = buffer;
+
+ while (len--) {
+ if (usart_read_byte(p) == 0) {
+ p++;
+ read++;
+ }
+ }
+
+ return read;
+}
+
+int usart_read_line(uint8_t *buffer, size_t len)
+{
+ uint8_t ch;
+ uint8_t *p = buffer;
+ size_t read = 0;
+
+ while (len--) {
+ if (usart_read_byte(&ch) != 0)
+ continue;
+ else
+ read++;
+
+ if (ch == '\n')
+ break;
+ else
+ *(p++) = ch;
+ }
+
+ if (ch != '\n')
+ return -1;
+
+ return 0;
+}
diff --git a/sw/programmer/avr/usart.h b/sw/programmer/avr/usart.h
new file mode 100644
index 0000000..1bb6607
--- /dev/null
+++ b/sw/programmer/avr/usart.h
@@ -0,0 +1,96 @@
+#ifndef __USART_H__
+#define __USART_H__
+/***
+ * USART REGISTERS {{{
+ *
+ * UCSR: control and status regisers, composed from 3 registers:
+ * +------------------------------------------------------------------------+
+ * | UCSRA :| RXC | TXC | UDRE | FE | DOR | PE | U2X | MPCM |
+ * +------------------------------------------------------------------------+
+ * UCSRA is a status register (read only)
+ * Relevant bits:
+ * - RXC : set to 1 if data is present on the receive buffer
+ * - TXC : set to 1 when data is transferred to the transfer register
+ * - UDRE: set to 1 when trasmit buffer is empty (data sent)
+ * +------------------------------------------------------------------------+
+ * | UCSRB :| RXCIE | TXCIE | UDRIE | RXEN | TXEN | UCSZ2 | RXB8 | TXB8 |
+ * +------------------------------------------------------------------------+
+ * UCSRB is used to setup hardware configuration
+ * Relevant bits:
+ * - RXCIE: RX complete interrupt enabled when set to 1
+ * - TXCIE: TX complete interrupt enabled when set to 1
+ * - UDRIE: data register empty interrupt enabled when set to 1
+ * - RXEN : uart receiver enabled when set to 1
+ * - TXEN : uart transmitter enabled when set to 1
+ * +------------------------------------------------------------------------+
+ * | UCSRC :| URSEL | UMSEL | UPM1 | UPM0 | USBS | UCSZ1 | UCSZ0 | UCPOL |
+ * +------------------------------------------------------------------------+
+ * UCSRB is used to setup protocol configuration
+ * Relevant bits:
+ * - URSEL: register select (location is shared with UBRRH and UCSRC)
+ * - UMSEL: mode select
+ * 1 -> synchronous
+ * 0 -> asynchronous
+ * - UMP1 + UPM0: set parity
+ * 00 -> no parity
+ * 01 -> reserved
+ * 10 -> even
+ * 11 -> odd
+ * - UCSZ2 + UCSZ1 + UCSZ0: set data frame (char size)
+ * 000 -> 5 bit
+ * 001 -> 6 bit
+ * 010 -> 7 bit
+ * 011 -> 8 bit
+ * 100 to 110 -> reserved
+ * 111 -> 9 bit
+ *
+ * UBRR: baudrate register
+ * +------------------------------------------------------------------------+
+ * | UBRRH :| URSEL | | | | UBRR11| UBRR10| UBRR9 | UBRR8 |
+ * +------------------------------------------------------------------------+
+ * | UBRRL :| UBRR7 | UBRR6 | UBRR5 | UBRR4 | UBRR3 | UBRR2 | UBRR1 | UBRR0 |
+ * +------------------------------------------------------------------------+
+ * UBRR is composed of 2 8 bit registers to store a 12 bit baudrate value.
+ * The value to be stored in this register is calculated with the following
+ * formula (approximate to integer):
+ * UBRR = ( XTAL_frequency ) / ( 16 * BAUDRATE ) -1
+ *
+ * in C code corresponds to:
+ * #define USART_BAUDRATE 9600
+ * #define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)
+ *
+ * Relevant bits:
+ * - URSEL: register select (location is share with UCSRC)
+ *
+ * UDR : data register
+ * This register is shared between RX and TX
+ *
+ * }}}
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <avr/io.h>
+
+#define USART_TIMEOUT 5000
+
+// struct usart_conf
+// {
+// uint16_t baudrate;
+// };
+
+void usart_init(uint16_t baudrate);
+// void usart_init_conf(struct usart_conf *conf);
+
+void usart_send_byte(uint8_t data);
+void usart_send(uint8_t *data, size_t len);
+
+void usart_print(char *str);
+
+int usart_read_byte(uint8_t *byte);
+uint8_t usart_read_byte_nt(void);
+size_t usart_read(uint8_t *buffer, size_t len);
+int uart_read_line(uint8_t *buffer, size_t len);
+
+#endif
diff --git a/sw/programmer/linux/config.h b/sw/programmer/linux/config.h
new file mode 100644
index 0000000..d319f43
--- /dev/null
+++ b/sw/programmer/linux/config.h
@@ -0,0 +1,26 @@
+/* config.h. Generated from config.h.in by configure. */
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Name of package */
+#define PACKAGE "z80prog"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "naopross@tharcway.org"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "z80prog"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "z80prog 0.1"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "z80prog"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "0.1"
+
+/* Version number of package */
+#define VERSION "0.1"
diff --git a/sw/programmer/linux/configure.ac b/sw/programmer/linux/configure.ac
new file mode 100644
index 0000000..a5c4b3b
--- /dev/null
+++ b/sw/programmer/linux/configure.ac
@@ -0,0 +1,23 @@
+AC_CONFIG_SRCDIR([src])
+AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_MACRO_DIR([m4])
+AC_CONFIG_AUX_DIR([build-aux])
+
+AC_INIT([z80prog], [0.1], [naopross@tharcway.org])
+AM_INIT_AUTOMAKE([-Wall -Werror foreign])
+
+AC_PROG_CC
+
+####
+# Check for required packages / libraries
+#
+LIBGTK_REQUIRED=2.91
+
+PKG_CHECK_MODULES(gtk3, [gtk+-3.0 >= $LIBGTK_REQUIRED])
+
+AC_CONFIG_FILES([
+ makefile
+ src/makefile
+])
+
+AC_OUTPUT
diff --git a/sw/programmer/linux/makefile.am b/sw/programmer/linux/makefile.am
new file mode 100644
index 0000000..4d27cea
--- /dev/null
+++ b/sw/programmer/linux/makefile.am
@@ -0,0 +1,2 @@
+SUBDIRS = src
+CLEANFILES = *~
diff --git a/sw/programmer/linux/reading_links.txt b/sw/programmer/linux/reading_links.txt
new file mode 100644
index 0000000..83c62f4
--- /dev/null
+++ b/sw/programmer/linux/reading_links.txt
@@ -0,0 +1,4 @@
+https://developer.gnome.org/gtk3/stable/ch01s04.html#id-1.2.3.12.5
+https://developer.gnome.org/gio/unstable/GApplication.html
+https://git.gnome.org/browse/gnome-hello/tree/src/app.c
+
diff --git a/sw/programmer/linux/src/main.c b/sw/programmer/linux/src/main.c
new file mode 100644
index 0000000..769992a
--- /dev/null
+++ b/sw/programmer/linux/src/main.c
@@ -0,0 +1,13 @@
+#include "config.h"
+#include "ui.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+int main(int argc, char *argv[])
+{
+ ui_init(&argc, &argv);
+ return 0;
+}
+
diff --git a/sw/programmer/linux/src/makefile.am b/sw/programmer/linux/src/makefile.am
new file mode 100644
index 0000000..492c3ec
--- /dev/null
+++ b/sw/programmer/linux/src/makefile.am
@@ -0,0 +1,7 @@
+bin_PROGRAMS = z80prog
+z80prog_SOURCES = main.c ui.c serial.c
+
+z80prog_CFLAGS = -Wall -Werror -g $(gtk3_CFLAGS)
+z80prog_LDADD = $(gtk3_LIBS)
+
+CLEANFILES = *~
diff --git a/sw/programmer/linux/src/serial.c b/sw/programmer/linux/src/serial.c
new file mode 100644
index 0000000..564676b
--- /dev/null
+++ b/sw/programmer/linux/src/serial.c
@@ -0,0 +1,42 @@
+#include "serial.h"
+
+int serial_connect(const char *devpath, long baudrate)
+{
+ int fd;
+ struct termios tty;
+ // struct termios tty_old;
+
+ // open device
+ if ((fd = open(devpath, O_RDWR | O_NOCTTY)) < 0) {
+ return -1;
+ }
+
+ // set parameters
+ if (tcgetattr(fd, &tty) != 0) {
+ return -1;
+ }
+
+ // TODO: update UI or add support for custom baudrate
+ // cfsetospeed(&tty,
+ // cfsetispeed(&tty,
+
+ tty.c_cflag &= ~PARENB; // no parity
+ tty.c_cflag &= ~CSTOPB; // no stop bit
+ tty.c_cflag |= CS8; // 8 bit data
+ tty.c_cflag &= ~CRTSCTS; // no flow control
+
+ tty.c_lflag = 0; // no signaling chars, no echo, no canonical processing
+ tty.c_oflag = 0; // no remapping, no delays
+ tty.c_cc[VMIN] = 0; // no block read
+ tty.c_cc[VTIME] = .5; // .5 seconds read timeout
+
+ tty.c_cflag |= CREAD | CLOCAL; // turn on read and ignore ctrl lines
+ tty.c_iflag &= ~(IXON | IXOFF | IXANY); // turn off s/w flow ctrl
+ tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // make raw
+ tty.c_oflag &= ~OPOST; // make raw
+
+ tcflush(fd , TCIFLUSH);
+ // if (tcsetaddr(
+
+ return fd;
+}
diff --git a/sw/programmer/linux/src/serial.h b/sw/programmer/linux/src/serial.h
new file mode 100644
index 0000000..6123e42
--- /dev/null
+++ b/sw/programmer/linux/src/serial.h
@@ -0,0 +1,17 @@
+#ifndef __Z80PROG_SERIAL_H__
+#define __Z80PROG_SERIAL_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <termios.h>
+
+int serial_connect(const char *devpath, long baudrate);
+void serial_close(int fd);
+
+void serial_program(const char *rompath);
+void serial_read_rom(const char *rom);
+
+#endif
diff --git a/sw/programmer/linux/src/ui.c b/sw/programmer/linux/src/ui.c
new file mode 100644
index 0000000..b33aa04
--- /dev/null
+++ b/sw/programmer/linux/src/ui.c
@@ -0,0 +1,90 @@
+#include "ui.h"
+
+static bool ui_connected, ui_fileset;
+static GtkTextBuffer *ui_logbuf;
+static GtkBuilder *ui_builder;
+
+void ui_init(int *argc, char **argv[])
+{
+ GtkWindow *window;
+ GtkTextView *logview;
+ GtkFileChooserButton *filechoosebtn;
+ GtkButton *connectbtn, *flashbtn;
+
+ /* set ui global variables */
+ ui_connected = ui_fileset = false;
+
+ /* start gtk */
+ gtk_init(argc, argv);
+
+ /* load glade gtk ui */
+ ui_builder = gtk_builder_new();
+ gtk_builder_add_from_file(ui_builder, "gbprog.ui", NULL);
+
+ /* connect logger buffer (extern variable) */
+ ui_logbuf = gtk_text_buffer_new(NULL);
+ logview = GTK_TEXT_VIEW(gtk_builder_get_object(ui_builder, "logview"));
+
+ gtk_text_view_set_buffer(logview, ui_logbuf);
+
+ /* connect objects to function calls */
+ // window
+ window = GTK_WINDOW(gtk_builder_get_object(ui_builder, "window"));
+ g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
+
+ // connectbtn
+ connectbtn = GTK_BUTTON(gtk_builder_get_object(ui_builder, "flashbtn"));
+ g_signal_connect(connectbtn, "clicked",
+ G_CALLBACK(ui_connect_clicked), NULL);
+
+ // flashbtn
+ flashbtn = GTK_BUTTON(gtk_builder_get_object(ui_builder, "flashbtn"));
+ g_signal_connect(flashbtn, "clicked", G_CALLBACK(ui_flash_clicked), NULL);
+
+ // file chooser
+ filechoosebtn = GTK_FILE_CHOOSER_BUTTON(
+ gtk_builder_get_object(ui_builder, "filechoosebtn"));
+ g_signal_connect(filechoosebtn, "file-set", G_CALLBACK(ui_file_set), NULL);
+
+ /* start gtk window */
+ gtk_main();
+}
+
+void ui_log(const char *msg, char type)
+{
+ GtkTextIter end;
+ gchar typech[4] = "[ ] ";
+
+ switch (type) {
+ case 'm': typech[1] = '@'; break; // message
+ case 'w': typech[1] = '#'; break; // warning
+ case 'e': typech[1] = '!'; break; // error
+ }
+
+ gtk_text_buffer_get_end_iter(ui_logbuf, &end);
+ gtk_text_buffer_insert(ui_logbuf, &end, typech, 4);
+ gtk_text_buffer_get_end_iter(ui_logbuf, &end);
+ gtk_text_buffer_insert(ui_logbuf, &end, (const gchar *) msg, strlen(msg));
+}
+
+void ui_file_set(GtkFileChooserButton *btn, gpointer user_data)
+{
+ GtkEntry *filepath =
+ GTK_ENTRY(gtk_builder_get_object(ui_builder, "filepath"));
+
+ gtk_entry_set_text(filepath,
+ gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(btn)));
+
+ ui_log("File set\n", 'm');
+ ui_fileset = true;
+}
+
+void ui_connect_clicked(void)
+{
+
+}
+
+void ui_flash_clicked(void)
+{
+
+}
diff --git a/sw/programmer/linux/src/ui.h b/sw/programmer/linux/src/ui.h
new file mode 100644
index 0000000..44314d6
--- /dev/null
+++ b/sw/programmer/linux/src/ui.h
@@ -0,0 +1,17 @@
+#ifndef __Z80PROG_UI_H__
+#define __Z80PROG_UI_H_
+
+#include <stdbool.h>
+#include <string.h>
+
+#include <gtk/gtk.h>
+
+void ui_init(int *argc, char **argv[]);
+void ui_log(const char *msg, char type);
+
+void ui_file_set(GtkFileChooserButton *btn, gpointer user_data);
+
+void ui_connect_clicked(void);
+void ui_flash_clicked(void);
+
+#endif
diff --git a/sw/programmer/linux/src/z80prog b/sw/programmer/linux/src/z80prog
new file mode 100755
index 0000000..878683b
--- /dev/null
+++ b/sw/programmer/linux/src/z80prog
Binary files differ
diff --git a/sw/programmer/linux/src/z80prog.ui b/sw/programmer/linux/src/z80prog.ui
new file mode 100644
index 0000000..3735efa
--- /dev/null
+++ b/sw/programmer/linux/src/z80prog.ui
@@ -0,0 +1,222 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.0 -->
+<interface>
+ <requires lib="gtk+" version="3.12"/>
+ <object class="GtkAdjustment" id="baudrateadjust">
+ <property name="upper">1000000</property>
+ <property name="value">9600</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkFileFilter" id="gbbinfilter">
+ <patterns>
+ <pattern>*.bin</pattern>
+ <pattern>*.gb</pattern>
+ <pattern>*.gba</pattern>
+ <pattern>*.gbc</pattern>
+ <pattern>*.hex</pattern>
+ </patterns>
+ </object>
+ <object class="GtkWindow" id="window">
+ <property name="width_request">450</property>
+ <property name="height_request">250</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="title" translatable="yes">Z80 ROM Programmer</property>
+ <property name="default_width">450</property>
+ <property name="default_height">200</property>
+ <child>
+ <object class="GtkBox" id="mainbox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_left">10</property>
+ <property name="margin_right">10</property>
+ <property name="margin_top">10</property>
+ <property name="margin_bottom">10</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">10</property>
+ <child>
+ <object class="GtkBox" id="devbox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">10</property>
+ <child>
+ <object class="GtkEntry" id="devpath">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="placeholder_text" translatable="yes">Enter path</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="devbaudrate">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="width_chars">0</property>
+ <property name="max_width_chars">7</property>
+ <property name="overwrite_mode">True</property>
+ <property name="placeholder_text" translatable="yes">9600</property>
+ <property name="input_purpose">number</property>
+ <property name="adjustment">baudrateadjust</property>
+ <property name="climb_rate">10</property>
+ <property name="snap_to_ticks">True</property>
+ <property name="numeric">True</property>
+ <property name="update_policy">if-valid</property>
+ <property name="value">9600</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="connectbtn">
+ <property name="label">gtk-connect</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="filebox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">10</property>
+ <child>
+ <object class="GtkEntry" id="filepath">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="placeholder_text" translatable="yes">Binary Path</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFileChooserButton" id="filechoosebtn">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="filter">gbbinfilter</property>
+ <property name="title" translatable="yes"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="flashbox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">10</property>
+ <child>
+ <object class="GtkProgressBar" id="flashbar">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="show_text">True</property>
+ <property name="ellipsize">start</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="flashbtn">
+ <property name="label" translatable="yes">Flash</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="logscrolled">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkViewport" id="logviewport">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkExpander" id="logexpander">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="expanded">True</property>
+ <property name="label_fill">True</property>
+ <property name="resize_toplevel">True</property>
+ <child>
+ <object class="GtkTextView" id="logview">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="editable">False</property>
+ <property name="monospace">True</property>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="loglabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Logs</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>