├── codeflash_ROMs ├── .gitignore ├── DET1D-4.04D │ ├── README.md │ └── mailstation-DET1D-codeflash-4.04D.bin ├── DET1-2.54Y │ ├── README.md │ └── mailstation-DET1-codeflash-2.54Y.bin ├── DET1-2.55Y │ ├── mailstation-DET1-dataflash.bin │ ├── mailstation-DET1-codeflash-2.55Y.bin │ └── README.md ├── DET1-2.54 │ ├── mailstation-DET1-codeflash-2.54.bin │ └── README.md ├── DET1-3.03 │ ├── README.md │ └── mailstation-DET1-codeflash-3.03.bin ├── DET1-3.03a │ ├── mailstation-DET1-codeflash-3.03a.bin │ └── README.md ├── DET1-2.53YR │ ├── mailstation-DET1-codeflash-2.53YR.bin │ └── README.md ├── DET1-1.73CID │ ├── mailstation-DET1-codeflash-1.73CID.bin │ └── README.md ├── README.md └── gen_disasm.sh ├── fonts └── msfont-3x5-mono.ttf ├── README.md ├── src ├── host │ ├── mailtransfer │ │ ├── inpout32.dll │ │ ├── mailtransfer.exe │ │ ├── makefile │ │ ├── README.md │ │ └── mailtransfer.c │ └── README.md ├── demos │ ├── drawimage │ │ ├── fybertechlogo.rle │ │ ├── .gitignore │ │ ├── README.md │ │ ├── makefile │ │ ├── graphicslcd.s │ │ ├── drawimage.s │ │ ├── fybertechlogo_rle.inc │ │ └── crt0-asm.s │ ├── blinkled │ │ ├── .gitignore │ │ ├── makefile │ │ └── blinkled.s │ ├── channels │ │ ├── .gitignore │ │ ├── makefile │ │ └── README.md │ ├── FyOS │ │ ├── v0.01 │ │ │ ├── .gitignore │ │ │ ├── fyos.h │ │ │ ├── makefile │ │ │ ├── scancode_table.inc │ │ │ ├── mailstation.h │ │ │ ├── getchar.s │ │ │ ├── crt0.s │ │ │ ├── fyos.c │ │ │ ├── mailstation.c │ │ │ └── cgafont.inc │ │ ├── v0.02 │ │ │ ├── .gitignore │ │ │ ├── fyos.h │ │ │ ├── makefile │ │ │ ├── scancode_table.inc │ │ │ ├── mailstation.h │ │ │ ├── getchar.s │ │ │ ├── crt0.s │ │ │ ├── fyos.c │ │ │ └── mailstation.c │ │ └── makefile │ ├── makefile │ └── README.md ├── tools │ ├── msloader │ │ ├── msloader-icon.bmp │ │ ├── .gitignore │ │ ├── msloader.h │ │ ├── interface.h │ │ ├── loadrun.h │ │ ├── parport_method.h │ │ ├── dump.h │ │ ├── save.h │ │ ├── trampoline.c │ │ ├── parport_method.c │ │ ├── interface.c │ │ ├── msloader-app_info.h │ │ ├── makefile │ │ ├── crt0-msloader-LDR.s │ │ ├── README.md │ │ ├── loadrun.c │ │ ├── msloader.c │ │ ├── LDR.s │ │ ├── dump.c │ │ └── save.c │ ├── msemu_4to8_loader │ │ ├── .gitignore │ │ ├── makefile │ │ ├── msemu_4to8_loader.s │ │ └── README.md │ ├── makefile │ └── README.md ├── mslib │ ├── .gitignore │ ├── makefile │ ├── lcd.c │ ├── keyboard.c │ ├── wifi_parport.c │ ├── msfw_parport.c │ ├── crt0-slot4.s │ ├── graphics-textmode.c │ └── dflash_write.c ├── makefile ├── include │ ├── lcd.h │ ├── led.h │ ├── msfw_parport.h │ ├── wifi_parport.h │ ├── keyboard.h │ ├── graphics-textmode.h │ ├── dflash_write.h │ ├── CFfuncs.h │ ├── dflash_app.h │ ├── ms_ports.h │ └── msfont_3x5.h └── README.md ├── templates └── dflash_app_icon_40x34.bmp ├── LICENSE └── scripts ├── icon_bmp_to_struct_init.sh └── ttf_to_header.sh /codeflash_ROMs/.gitignore: -------------------------------------------------------------------------------- 1 | disasm/ 2 | -------------------------------------------------------------------------------- /codeflash_ROMs/DET1D-4.04D/README.md: -------------------------------------------------------------------------------- 1 | # Firmware Rev 4.04D 2 | 3 | Dumped from Mivo 150 unit. 4 | -------------------------------------------------------------------------------- /fonts/msfont-3x5-mono.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kbembedded/mailstation/HEAD/fonts/msfont-3x5-mono.ttf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | See the [Mailstation wiki](https://github.com/kbembedded/mailstation/wiki/) for the most up to date information. 2 | -------------------------------------------------------------------------------- /src/host/mailtransfer/inpout32.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kbembedded/mailstation/HEAD/src/host/mailtransfer/inpout32.dll -------------------------------------------------------------------------------- /templates/dflash_app_icon_40x34.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kbembedded/mailstation/HEAD/templates/dflash_app_icon_40x34.bmp -------------------------------------------------------------------------------- /src/demos/drawimage/fybertechlogo.rle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kbembedded/mailstation/HEAD/src/demos/drawimage/fybertechlogo.rle -------------------------------------------------------------------------------- /src/tools/msloader/msloader-icon.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kbembedded/mailstation/HEAD/src/tools/msloader/msloader-icon.bmp -------------------------------------------------------------------------------- /src/demos/blinkled/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.lst 3 | *.sym 4 | *.lnk 5 | *.rel 6 | *.ihx 7 | *.bin 8 | *.map 9 | *.lk 10 | *.noi 11 | -------------------------------------------------------------------------------- /src/demos/channels/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.lst 3 | *.sym 4 | *.lnk 5 | *.rel 6 | *.ihx 7 | *.bin 8 | *.map 9 | *.lk 10 | *.noi 11 | -------------------------------------------------------------------------------- /src/demos/drawimage/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.lst 3 | *.sym 4 | *.lnk 5 | *.rel 6 | *.ihx 7 | *.bin 8 | *.map 9 | *.lk 10 | *.noi 11 | -------------------------------------------------------------------------------- /src/host/README.md: -------------------------------------------------------------------------------- 1 | # Host PC tools for Mailstation 2 | Inside these subfolders are tools for host PCs to interact with the Mailstation 3 | -------------------------------------------------------------------------------- /src/host/mailtransfer/mailtransfer.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kbembedded/mailstation/HEAD/src/host/mailtransfer/mailtransfer.exe -------------------------------------------------------------------------------- /src/tools/msemu_4to8_loader/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.lst 3 | *.sym 4 | *.lnk 5 | *.rel 6 | *.ihx 7 | *.bin 8 | *.map 9 | *.lk 10 | *.noi 11 | -------------------------------------------------------------------------------- /src/demos/FyOS/v0.01/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.lst 3 | *.sym 4 | *.lnk 5 | *.rel 6 | *.ihx 7 | *.bin 8 | *.map 9 | *.lk 10 | *.noi 11 | *.asm 12 | -------------------------------------------------------------------------------- /src/demos/FyOS/v0.02/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.lst 3 | *.sym 4 | *.lnk 5 | *.rel 6 | *.ihx 7 | *.bin 8 | *.map 9 | *.lk 10 | *.noi 11 | *.asm 12 | -------------------------------------------------------------------------------- /src/mslib/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.lst 3 | *.sym 4 | *.lnk 5 | *.rel 6 | *.ihx 7 | *.bin 8 | *.map 9 | *.lk 10 | *.noi 11 | *.asm 12 | *.lib 13 | -------------------------------------------------------------------------------- /src/tools/msloader/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.lst 3 | *.sym 4 | *.lnk 5 | *.rel 6 | *.ihx 7 | *.bin 8 | *.bin.h 9 | *.map 10 | *.lk 11 | *.noi 12 | *.asm 13 | -------------------------------------------------------------------------------- /codeflash_ROMs/DET1-2.54Y/README.md: -------------------------------------------------------------------------------- 1 | # Firmware Rev 2.54Y 2 | 3 | Dumped via Code Dumper app. 4 | 5 | Checksum of ROM in Mailstation diagnostic menu is `610E`. 6 | -------------------------------------------------------------------------------- /codeflash_ROMs/DET1-2.55Y/mailstation-DET1-dataflash.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kbembedded/mailstation/HEAD/codeflash_ROMs/DET1-2.55Y/mailstation-DET1-dataflash.bin -------------------------------------------------------------------------------- /codeflash_ROMs/DET1-2.54/mailstation-DET1-codeflash-2.54.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kbembedded/mailstation/HEAD/codeflash_ROMs/DET1-2.54/mailstation-DET1-codeflash-2.54.bin -------------------------------------------------------------------------------- /codeflash_ROMs/DET1-3.03/README.md: -------------------------------------------------------------------------------- 1 | # Firmware Rev 3.03 2 | 3 | Dumped with `maildump` and `spew` process 4 | 5 | Checksum of ROM in Mailstation diagnostic menu is FCC6 6 | -------------------------------------------------------------------------------- /codeflash_ROMs/DET1-3.03/mailstation-DET1-codeflash-3.03.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kbembedded/mailstation/HEAD/codeflash_ROMs/DET1-3.03/mailstation-DET1-codeflash-3.03.bin -------------------------------------------------------------------------------- /codeflash_ROMs/DET1-2.54Y/mailstation-DET1-codeflash-2.54Y.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kbembedded/mailstation/HEAD/codeflash_ROMs/DET1-2.54Y/mailstation-DET1-codeflash-2.54Y.bin -------------------------------------------------------------------------------- /codeflash_ROMs/DET1-2.55Y/mailstation-DET1-codeflash-2.55Y.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kbembedded/mailstation/HEAD/codeflash_ROMs/DET1-2.55Y/mailstation-DET1-codeflash-2.55Y.bin -------------------------------------------------------------------------------- /codeflash_ROMs/DET1-3.03a/mailstation-DET1-codeflash-3.03a.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kbembedded/mailstation/HEAD/codeflash_ROMs/DET1-3.03a/mailstation-DET1-codeflash-3.03a.bin -------------------------------------------------------------------------------- /codeflash_ROMs/DET1-2.53YR/mailstation-DET1-codeflash-2.53YR.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kbembedded/mailstation/HEAD/codeflash_ROMs/DET1-2.53YR/mailstation-DET1-codeflash-2.53YR.bin -------------------------------------------------------------------------------- /codeflash_ROMs/DET1D-4.04D/mailstation-DET1D-codeflash-4.04D.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kbembedded/mailstation/HEAD/codeflash_ROMs/DET1D-4.04D/mailstation-DET1D-codeflash-4.04D.bin -------------------------------------------------------------------------------- /codeflash_ROMs/DET1-1.73CID/mailstation-DET1-codeflash-1.73CID.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kbembedded/mailstation/HEAD/codeflash_ROMs/DET1-1.73CID/mailstation-DET1-codeflash-1.73CID.bin -------------------------------------------------------------------------------- /codeflash_ROMs/DET1-3.03a/README.md: -------------------------------------------------------------------------------- 1 | # Firmware Rev 3.03a 2 | 3 | Retrieved from Yahoo! group and also verified on a real unit. 4 | 5 | Checksum of ROM in Mailstation diagnostic menu is 53E5 6 | -------------------------------------------------------------------------------- /src/demos/makefile: -------------------------------------------------------------------------------- 1 | SUBDIRS := $(wildcard */.) 2 | 3 | .PHONY: clean all $(SUBDIRS) 4 | 5 | all: $(SUBDIRS) 6 | clean: $(SUBDIRS) 7 | 8 | $(SUBDIRS): 9 | $(MAKE) -C $@ $(MAKECMDGOALS) 10 | -------------------------------------------------------------------------------- /src/tools/makefile: -------------------------------------------------------------------------------- 1 | SUBDIRS := $(wildcard */.) 2 | 3 | .PHONY: clean all $(SUBDIRS) 4 | 5 | all: $(SUBDIRS) 6 | clean: $(SUBDIRS) 7 | 8 | $(SUBDIRS): 9 | $(MAKE) -C $@ $(MAKECMDGOALS) 10 | -------------------------------------------------------------------------------- /src/demos/FyOS/makefile: -------------------------------------------------------------------------------- 1 | SUBDIRS := $(wildcard */.) 2 | 3 | .PHONY: clean all $(SUBDIRS) 4 | 5 | all: $(SUBDIRS) 6 | clean: $(SUBDIRS) 7 | 8 | $(SUBDIRS): 9 | $(MAKE) -C $@ $(MAKECMDGOALS) 10 | -------------------------------------------------------------------------------- /codeflash_ROMs/DET1-1.73CID/README.md: -------------------------------------------------------------------------------- 1 | # Firmware Rev 1.73CID 2 | 3 | Firmware from Southwestern Bell eMessage-branded DET1, dumped via 4 | Code Dumper app. 5 | 6 | Checksum of ROM in Mailstation diagnostic menu is `C666`. 7 | -------------------------------------------------------------------------------- /src/makefile: -------------------------------------------------------------------------------- 1 | SUBDIRS := $(wildcard */.) 2 | SUBDIRS := $(filter-out include/. host/., $(SUBDIRS)) 3 | 4 | .PHONY: clean all $(SUBDIRS) 5 | 6 | all: $(SUBDIRS) 7 | clean: $(SUBDIRS) 8 | 9 | $(SUBDIRS): 10 | $(MAKE) -C $@ $(MAKECMDGOALS) 11 | -------------------------------------------------------------------------------- /src/tools/msloader/msloader.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | /* Copyright (c) 2020 KBEmbedded */ 3 | 4 | #ifndef __MSLOADER_H__ 5 | #define __MSLOADER_H__ 6 | 7 | void go_to_main(void); 8 | 9 | #endif // __MSLOADER_H__ 10 | -------------------------------------------------------------------------------- /src/include/lcd.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | /* Copyright (c) 2020 KBEmbedded */ 3 | 4 | #ifndef __LCD_H__ 5 | #define __LCD_H__ 6 | 7 | void lcd_buf_clr(void); 8 | void lcd_update(void); 9 | 10 | #endif // __LCD_H__ 11 | -------------------------------------------------------------------------------- /src/host/mailtransfer/makefile: -------------------------------------------------------------------------------- 1 | MINGW_WIN32=i686-w64-mingw32 2 | CC=$(MINGW_WIN32)-gcc 3 | STRIP=$(MINGW_WIN32)-strip 4 | 5 | all: mailtransfer.exe 6 | 7 | mailtransfer.exe: mailtransfer.c 8 | $(CC) -o $@ $< 9 | $(STRIP) $@ 10 | 11 | clean: 12 | rm *.exe 13 | -------------------------------------------------------------------------------- /src/include/led.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | /* Copyright (c) 2020 KBEmbedded */ 3 | 4 | #ifndef __LED_H__ 5 | #define __LED_H__ 6 | 7 | #define msfw_set_led(x) ((void (*)(uint16_t)) 0x0A77)(x) 8 | void set_led(char val); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /codeflash_ROMs/DET1-2.54/README.md: -------------------------------------------------------------------------------- 1 | # Firmware Rev 2.54 2 | 3 | Originally from Yahoo! group files dump. Have verified this in emulator, not on a real unit. 4 | 5 | Checksum of ROM in Mailstation diagnostic menu in `msemu` is 4807 6 | 7 | The text files in this directory were originally posted in the Yahoo! group. 8 | -------------------------------------------------------------------------------- /src/demos/FyOS/v0.01/fyos.h: -------------------------------------------------------------------------------- 1 | #ifndef __FYOS_H__ 2 | #define __FYOS_H__ 3 | // Pointer to the Mailstation firmware version 4 | // versionpointer[0] is the minor version 5 | // versionpointer[1] is the major version 6 | volatile unsigned char *versionpointer = (volatile unsigned char *)0x0036; 7 | #endif // __FYOS_H__ 8 | -------------------------------------------------------------------------------- /src/demos/FyOS/v0.02/fyos.h: -------------------------------------------------------------------------------- 1 | #ifndef __FYOS_H__ 2 | #define __FYOS_H__ 3 | // Pointer to the Mailstation firmware version 4 | // versionpointer[0] is the minor version 5 | // versionpointer[1] is the major version 6 | volatile unsigned char *versionpointer = (volatile unsigned char *)0x0036; 7 | #endif // __FYOS_H__ 8 | -------------------------------------------------------------------------------- /src/include/msfw_parport.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | /* Copyright (c) 2020 KBEmbedded */ 3 | 4 | #ifndef __MSFW_PARPORT_H__ 5 | #define __MSFW_PARPORT_H__ 6 | 7 | uint16_t msfw_parport_read_byte(void); 8 | uint16_t msfw_parport_write_byte(uint8_t val); 9 | 10 | #endif // __MSFW_PARPORT_H__ 11 | -------------------------------------------------------------------------------- /src/include/wifi_parport.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | /* Copyright (c) 2021 KBEmbedded */ 3 | 4 | #ifndef __WIFI_PARPORT_H__ 5 | #define __WIFI_PARPORT_H__ 6 | 7 | void wifi_parport_prepare(void); 8 | uint16_t wifi_parport_read_byte(void); 9 | uint16_t wifi_parport_write_byte(uint8_t val); 10 | 11 | #endif // __WIFI_PARPORT_H__ 12 | -------------------------------------------------------------------------------- /codeflash_ROMs/DET1-2.53YR/README.md: -------------------------------------------------------------------------------- 1 | # Firmware Rev 2.53YR 2 | 3 | Originally from Yahoo! group files dump. Have verified this in emulator, not on a real unit. It needed to be assembled from paged dump files. 4 | 5 | Checksum of ROM in Mailstation diagnostic menu in `msemu` is 9254 6 | 7 | The text files in this directory were originally posted in the Yahoo! group. 8 | -------------------------------------------------------------------------------- /codeflash_ROMs/DET1-2.55Y/README.md: -------------------------------------------------------------------------------- 1 | # Firmware Rev 2.55Y 2 | 3 | Desoldered and dumped directly as well as verified against `maildump` and `spew` process 4 | 5 | Checksum of ROM in Mailstation diagnostic menu is BA7C 6 | 7 | The dataflash file in here was desolderd and dumped directly. There is nothing useful on it really, just here as a reference of what is a valid dataflash image structure. 8 | -------------------------------------------------------------------------------- /src/demos/drawimage/README.md: -------------------------------------------------------------------------------- 1 | # Drawimage 2 | A demo to showcase drawing images to the screen. A single demo that can be compiled in two different ways (by changing the source code slightly) to put a cityscape image or "Fybertech" logo on the screen. 3 | 4 | This uses a function in its own file that was pulled from the Mailstation firmware. It was copied in to its own file for ease of use as a demo. 5 | -------------------------------------------------------------------------------- /src/host/mailtransfer/README.md: -------------------------------------------------------------------------------- 1 | # Mailtransfer 2 | Send / recv files between a Mailstation and host PC 3 | 4 | Currently can only send file up to 65535 bytes, only meant to send Dataflash applications at this time. 5 | 6 | Can receive any size file, however, this size needs to be known ahead of time by both parties. 7 | 8 | Otherwise behaves the same as the original mailsend and maildump from the Yahoo! group. 9 | -------------------------------------------------------------------------------- /src/demos/blinkled/makefile: -------------------------------------------------------------------------------- 1 | 2 | CC = sdcc 3 | CFLAGS = -mz80 4 | LDFLAGS = --no-std-crt0 --code-loc 0x8000 --data-loc 0x8000 5 | AS = sdasz80 6 | ASFLAGS = -lso 7 | 8 | all: blinkled.bin 9 | 10 | %.bin: %.ihx 11 | objcopy -Iihex -Obinary $< $@ 12 | 13 | %.rel: %.s 14 | $(AS) $(ASFLAGS) $< 15 | 16 | %.ihx: %.rel 17 | $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ 18 | 19 | clean: 20 | rm -f *.rel *.ihx *.bin *.lk *.sym *.lst *.noi *.map *.asm 21 | -------------------------------------------------------------------------------- /src/demos/channels/makefile: -------------------------------------------------------------------------------- 1 | 2 | CC = sdcc 3 | CFLAGS = -mz80 4 | LDFLAGS = --no-std-crt0 --code-loc 0x4000 --data-loc 0x4000 5 | AS = sdasz80 6 | ASFLAGS = -lso 7 | 8 | all: tvlisting.bin weather.bin topstories.bin MIlotto.bin 9 | 10 | %.bin: %.ihx 11 | objcopy -Iihex -Obinary $< $@ 12 | 13 | %.rel: %.s 14 | $(AS) $(ASFLAGS) $< 15 | 16 | %.ihx: %.rel 17 | $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ 18 | 19 | clean: 20 | rm -f *.rel *.ihx *.bin *.lk *.sym *.lst *.noi *.map *.asm 21 | -------------------------------------------------------------------------------- /src/tools/msloader/interface.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | /* Copyright (c) 2020 KBEmbedded */ 3 | 4 | #ifndef __INTERFACE_H__ 5 | #define __INTERFACE_H__ 6 | 7 | #include 8 | 9 | struct opt_tbl { 10 | char *string; 11 | void (*func)(void); 12 | }; 13 | 14 | extern const struct opt_tbl *cur_opts; 15 | extern uint8_t line; 16 | extern uint8_t line_max; 17 | 18 | void draw_header(void); 19 | void draw_options(void); 20 | 21 | #endif // __INTERFACE_H__ 22 | -------------------------------------------------------------------------------- /src/include/keyboard.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | /* Copyright (c) 2020 KBEmbedded */ 3 | 4 | #ifndef __KEYBOARD_H__ 5 | #define __KEYBOARD_H__ 6 | 7 | 8 | /* Returns 1 if a valid scancode is available. Sets the scancode data 9 | * in two bytes passed in argument. 10 | */ 11 | #define msfw_get_scancode(x) ((uint8_t (*)(uint8_t *)) 0x0A9A)(x) 12 | 13 | extern const char scode_lower[160]; 14 | 15 | void kbd_flush(void); 16 | void kbd_anykey(void); 17 | 18 | #endif // __KEYBOARD_H__ 19 | -------------------------------------------------------------------------------- /src/include/graphics-textmode.h: -------------------------------------------------------------------------------- 1 | #ifndef __GRAPHICS_TEXTMODE_H__ 2 | #define __GRAPHICS_TEXTMODE_H__ 3 | 4 | void g_textmode_set_invert(uint8_t inv); 5 | void g_textmode_clear_line(uint8_t line); 6 | void g_textmode_invert_line(uint8_t line); 7 | void g_textmode_set_ypos(uint8_t new_pos); 8 | void g_textmode_set_xpos(uint8_t new_pos); 9 | uint8_t g_textmode_get_ypos(void); 10 | uint8_t g_textmode_get_xpos(void); 11 | void g_textmode_init(void); 12 | int putchar(int val); 13 | //void putchar(char val); 14 | 15 | #endif // __GRAPHICS_TEXTMODE_H__ 16 | -------------------------------------------------------------------------------- /src/tools/msloader/loadrun.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | /* Copyright (c) 2020 KBEmbedded */ 3 | 4 | #ifndef __LOADRUN_H__ 5 | #define __LOADRUN_H__ 6 | 7 | #include 8 | 9 | uint16_t load_from_parport(volatile uint8_t *buf); 10 | void loadrun_from_parport(void); 11 | void loadrun_from_8000(void); 12 | void loadrun_from_4000(void); 13 | 14 | void sel_parport_msfw(void); 15 | void sel_parport_wifi(void); 16 | void sel_parport(void); 17 | 18 | extern const struct opt_tbl loadrun_opts[]; 19 | 20 | #endif // __LOADRUN_H__ 21 | -------------------------------------------------------------------------------- /src/tools/README.md: -------------------------------------------------------------------------------- 1 | # Tools 2 | Tools for development/testing/bootstrapping a Mailstation 3 | 4 | Running `make` from this directory will build all buildable files in subdirectories. 5 | 6 | 7 | ## Structure 8 | * `msloader/` - Contains Mailstation tools for loading applications to Mailstation via parallel port. See the `src/host/` directory for the PC side of the transfer process 9 | * `msemu_4to8_loader/` - Handy tool for emulating stage 0 parallel port loading with [msemu](https://github.com/kbembedded/msemu) (see README in folder for more information) 10 | -------------------------------------------------------------------------------- /src/README.md: -------------------------------------------------------------------------------- 1 | # Sources 2 | Mixed sources for both Mailstation and host utilities 3 | 4 | Running `make` from this directory will build all buildable files in subdirectories. 5 | 6 | 7 | ## Structure 8 | * `demos/` - Contains misc demos, samples, and other standalone things 9 | * `include/` - Contains headers for `mslib/` source files 10 | * `host/` - Contains tools/utils/etc. for host PC systems 11 | * `mslib/` - Contains common ASM and C sources useful in other areas 12 | * `tools/` - Contains tools useful for development/testing/bootstrapping a Mailstation 13 | -------------------------------------------------------------------------------- /src/demos/README.md: -------------------------------------------------------------------------------- 1 | # Demos 2 | Various demos for Mailstation 3 | 4 | Running `make` from this directory will build all buildable files in subdirectories. 5 | 6 | 7 | ## Structure 8 | * `blinkled/` - Contains a simple demo to blink the "New Mail" LED 9 | * `channels/` - Contains a couple of disassembled and buildable Mailstation "Channels" 10 | * `drawimage/` - Contains a demo to draw an image to the screen, both raw and with RLE encoding 11 | * `FyOS/` - Contains separate folders for different versions of FyOS, a custom command interpreter for the Mailstation 12 | -------------------------------------------------------------------------------- /src/include/dflash_write.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | /* Copyright (c) 2020 KBEmbedded */ 3 | 4 | #ifndef __DATAFLASH_H__ 5 | #define __DATAFLASH_H__ 6 | 7 | static void dflash_sdp_seq(void); 8 | 9 | static void dflash_wait_write(void); 10 | 11 | void dflash_unlock(void); 12 | 13 | void dflash_lock(void); 14 | 15 | uint8_t dflash_erase_sector(uint16_t adr); 16 | void dflash_erase_chip(void); 17 | 18 | uint8_t dflash_write_byte(uint16_t adr, uint8_t dat); 19 | uint8_t dflash_write_sector(uint16_t adr, uint8_t *dat); 20 | #endif // __DATAFLASH_H__ 21 | -------------------------------------------------------------------------------- /codeflash_ROMs/README.md: -------------------------------------------------------------------------------- 1 | # Mailstation ROM firmware dumps 2 | 3 | These folders contain direct codeflash dumps from various firmware revisions of different Mailstation models. Most of these were dumped using `maildump` and `spew`. This process was verified on a few units by directly dumping the contents of the flash chips themselves. 4 | 5 | Some firmware will have some specific comments or notes. Anything of real note that is common to all firmware versions are listed below. 6 | 7 | ## Adding new firmware images 8 | 9 | If you have access to a firmware version that is not listed here, nor the means to dump the firmware, please reach out to me as I would like to get a hold of it. 10 | -------------------------------------------------------------------------------- /src/tools/msloader/parport_method.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | /* Copyright (c) 2020 KBEmbedded */ 3 | 4 | #ifndef __PARPORT_METHOD_H__ 5 | #define __PARPORT_METHOD_H__ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "CFfuncs.h" 12 | #include "ms_ports.h" 13 | #include "msfw_parport.h" 14 | #include "wifi_parport.h" 15 | 16 | 17 | void sel_parport_msfw(void); 18 | void sel_parport_wifi(void); 19 | void sel_parport(void); 20 | 21 | extern uint16_t (*parport_read_ptr)(void); 22 | extern uint16_t (*parport_write_ptr)(uint8_t); 23 | 24 | extern const struct opt_tbl parport_opts[]; 25 | 26 | #endif // __PARPORT_METHOD_H__ 27 | -------------------------------------------------------------------------------- /src/mslib/makefile: -------------------------------------------------------------------------------- 1 | 2 | INCLUDES = -I$(CURDIR)/../include/ 3 | CC = sdcc 4 | CFLAGS = $(INCLUDES) -mz80 5 | AS = sdasz80 6 | AR = sdar 7 | ASFLAGS = -lso 8 | ASFLAGS_CRT0 := $(ASFLAGS) -g 9 | 10 | 11 | OBJS = dflash_write.rel graphics-textmode.rel lcd.rel msfw_parport.rel \ 12 | wifi_parport.rel keyboard.rel 13 | 14 | all: mslib.lib crt0-slot4.rel 15 | 16 | mslib.lib: $(OBJS) 17 | $(AR) -rc $@ $^ 18 | 19 | # crt0 sources need to be assembled with -g 20 | crt0%rel: crt0%s 21 | $(AS) $(ASFLAGS_CRT0) $< 22 | 23 | %.rel: %.s 24 | $(AS) $(ASFLAGS) $< 25 | 26 | %.rel: %.c 27 | $(CC) $(CFLAGS) -c $< 28 | 29 | clean: 30 | rm -f *.rel *.ihx *.bin *.lk *.sym *.lst *.noi *.map *.asm *.lib 31 | -------------------------------------------------------------------------------- /src/tools/msemu_4to8_loader/makefile: -------------------------------------------------------------------------------- 1 | 2 | CC = sdcc 3 | CFLAGS = -mz80 --no-std-crt0 --code-loc 0x4000 --data-loc 0x4000 4 | AS = sdasz80 5 | ASFLAGS = -lso 6 | 7 | all: clean msemu_4to8_loader.bin append_bin write_df 8 | 9 | append_bin: msemu_4to8_loader.bin 10 | ifdef bin 11 | cat $< $(bin) > msemu_4to8_loader-app.bin 12 | endif 13 | 14 | write_df: append_bin 15 | ifdef df_out 16 | @echo Writing application to start of dataflash 17 | dd if=msemu_4to8_loader-app.bin of=$(df_out) conv=notrunc 18 | endif 19 | 20 | %.bin: %.ihx 21 | objcopy -Iihex -Obinary $< $@ 22 | 23 | %.ihx: %.rel 24 | $(CC) $(CFLAGS) $< -o $@ 25 | 26 | %.rel: %.s 27 | $(AS) $(ASFLAGS) $< 28 | 29 | clean: 30 | rm -f *.rel *.ihx *.bin *.lk *.sym *.lst *.noi *.map 31 | -------------------------------------------------------------------------------- /src/demos/FyOS/v0.01/makefile: -------------------------------------------------------------------------------- 1 | 2 | CC = sdcc 3 | CFLAGS = -mz80 4 | LDFLAGS = --no-std-crt0 --code-loc 0x8100 --data-loc 0x0000 5 | AS = sdasz80 6 | ASFLAGS = -lso 7 | ASFLAGS_CRT0 := $(ASFLAGS) -g 8 | 9 | # NOTE: sdcc has a gotcha that crt0.rel MUST be first file the command line 10 | # if passing --no-std-crt0 during linking phase 11 | LOCAL_OBJS = crt0.rel getchar.rel putchar.rel fyos.rel mailstation.rel 12 | 13 | 14 | OBJS = $(LOCAL_OBJS) 15 | 16 | all: FyOS-v001.bin $(OBJS) 17 | 18 | # crt0 sources need to be assembled with -g 19 | crt0%rel: crt0%s 20 | $(AS) $(ASFLAGS_CRT0) $< 21 | 22 | %.bin: %.ihx 23 | objcopy -Iihex -Obinary $< $@ 24 | 25 | %.rel: %.c 26 | $(CC) $(CFLAGS) -c $< 27 | 28 | %.rel: %.s 29 | $(AS) $(ASFLAGS) $< 30 | 31 | %.ihx: $(OBJS) 32 | $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) -o $@ 33 | 34 | clean: 35 | rm -f *.rel *.ihx *.bin *.lk *.sym *.lst *.noi *.map *.asm 36 | -------------------------------------------------------------------------------- /src/demos/FyOS/v0.02/makefile: -------------------------------------------------------------------------------- 1 | 2 | CC = sdcc 3 | CFLAGS = -mz80 4 | LDFLAGS = --no-std-crt0 --code-loc 0x8100 --data-loc 0x0000 5 | AS = sdasz80 6 | ASFLAGS = -lso 7 | ASFLAGS_CRT0 := $(ASFLAGS) -g 8 | 9 | # NOTE: sdcc has a gotcha that crt0.rel MUST be first file the command line 10 | # if passing --no-std-crt0 during linking phase 11 | LOCAL_OBJS = crt0.rel getchar.rel putchar.rel fyos.rel mailstation.rel 12 | 13 | 14 | OBJS = $(LOCAL_OBJS) 15 | 16 | all: FyOS-v002.bin $(OBJS) 17 | 18 | # crt0 sources need to be assembled with -g 19 | crt0%rel: crt0%s 20 | $(AS) $(ASFLAGS_CRT0) $< 21 | 22 | %.bin: %.ihx 23 | objcopy -Iihex -Obinary $< $@ 24 | 25 | %.rel: %.c 26 | $(CC) $(CFLAGS) -c $< 27 | 28 | %.rel: %.s 29 | $(AS) $(ASFLAGS) $< 30 | 31 | %.ihx: $(OBJS) 32 | $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) -o $@ 33 | 34 | clean: 35 | rm -f *.rel *.ihx *.bin *.lk *.sym *.lst *.noi *.map *.asm 36 | -------------------------------------------------------------------------------- /src/tools/msloader/dump.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | /* Copyright (c) 2020 KBEmbedded */ 3 | #ifndef __DUMP_H__ 4 | #define __DUMP_H__ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include "CFfuncs.h" 11 | #include "dflash_write.h" 12 | #include "graphics-textmode.h" 13 | #include "lcd.h" 14 | #include "led.h" 15 | #include "ms_ports.h" 16 | #include "msfw_parport.h" 17 | #include "wifi_parport.h" 18 | 19 | void dump_to_parport(void); 20 | void dump_dflash(void); 21 | void dump_cflash(void); 22 | void send_to_parport(void); 23 | void send_self_run_8000(void); 24 | void send_self_run_4000(void); 25 | void send_0(void); 26 | void send_1(void); 27 | void send_2(void); 28 | void send_3(void); 29 | void send_4(void); 30 | 31 | extern const struct opt_tbl dump_opts[]; 32 | 33 | extern const struct opt_tbl send_opts[]; 34 | 35 | 36 | #endif // __DUMP_H__ 37 | -------------------------------------------------------------------------------- /src/include/CFfuncs.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | /* Copyright (c) 2020 KBEmbedded */ 3 | 4 | #ifndef __CFFUNCS_H__ 5 | #define __CFFUNCS_H__ 6 | 7 | /* A list of various functions provided by stock Mailstation firmware. Where 8 | * appropriate, a list of known compatible or incompatible firmware versions 9 | * will be listed as well. 10 | * 11 | * To the best of current knowledge, these functions are safe to run from any 12 | * context and do not require 13 | */ 14 | 15 | /**************************************************************************** 16 | * Delay for ms value 17 | * 18 | * Delay for miliseconds of time 19 | */ 20 | #define msfw_delay(x) ((void (*)(uint16_t)) 0x0A5C)(x) 21 | 22 | 23 | /**************************************************************************** 24 | * Power off Mailstation 25 | * 26 | * Simply shuts off mailstation as if the power button were pressed. 27 | */ 28 | #define msfw_poweroff ((void (*)(void)) 0x0A6B) 29 | 30 | #endif // __CFFUNCS_H__ 31 | -------------------------------------------------------------------------------- /src/tools/msloader/save.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | /* Copyright (c) 2020 KBEmbedded */ 3 | 4 | #ifndef __SAVE_H__ 5 | #define __SAVE_H__ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "CFfuncs.h" 12 | #include "dflash_write.h" 13 | #include "graphics-textmode.h" 14 | #include "lcd.h" 15 | #include "led.h" 16 | #include "ms_ports.h" 17 | #include "msfw_parport.h" 18 | #include "wifi_parport.h" 19 | 20 | void loadsave_from_parport(void); 21 | 22 | /* Use 0 to disable all channels */ 23 | uint8_t enable_channel_max(uint8_t max); 24 | void self_write_to_app0(void); 25 | void manage_dflash(void); 26 | void chan_dis(void); 27 | void chan_en0(void); 28 | void chan_en1(void); 29 | void chan_en2(void); 30 | void chan_en3(void); 31 | void chan_en4(void); 32 | extern const struct opt_tbl manage_dflash_opts[]; 33 | 34 | void loadsave_to_0(void); 35 | void loadsave_to_1(void); 36 | void loadsave_to_2(void); 37 | void loadsave_to_3(void); 38 | void loadsave_to_4(void); 39 | 40 | extern const struct opt_tbl loadsave_opts[]; 41 | 42 | #endif // __SAVE_H__ 43 | -------------------------------------------------------------------------------- /src/include/dflash_app.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | /* Copyright (c) 2020 KBEmbedded */ 3 | 4 | #ifndef __DFLASH_APP_H__ 5 | #define __DFLASH_APP_H__ 6 | 7 | #include 8 | 9 | typedef const struct dataflash_name { 10 | uint16_t unknown; // Unknown meaning, should be 0x0001 11 | uint16_t name_len; // Length of name, not including \0! 12 | uint16_t name_start; // Relative to start of struct, likely always 0x0006 13 | char name[]; // Unsure of useful effective length 14 | } dataflash_name; 15 | 16 | typedef const struct dataflash_icon_no_icon1 { 17 | uint16_t icon0_size; // This will likely always be 0x00AD 18 | uint16_t icon0_start; // Start of icon0_width, likely always 0x0008 19 | uint16_t icon1_size; // This will likely always be 0x0000 20 | uint16_t icon1_start; // This is relative to the start of the struct 21 | 22 | uint16_t icon0_width; // This will likely always be 0x0022 (34) 23 | uint8_t icon0_height; // This will likely always be 0x0022 (34) 24 | uint8_t icon0[][]; // 34 rows, 5 bytes each, to represent 34x34 25 | } dataflash_icon_no_icon1; 26 | 27 | 28 | #endif // __DFLASH_APP_H__ 29 | -------------------------------------------------------------------------------- /src/demos/blinkled/blinkled.s: -------------------------------------------------------------------------------- 1 | .module blinkled 2 | ; This functions in an infinite loop, just changing the LED state once 3 | ; every second. A helper function from ROM is used to accomplish this. 4 | 5 | ; Once this runs, its basically stuck here. There is a way to return to 6 | ; the Mailstation main OS as seen in other, official apps, but how this 7 | ; is accomplished is not yet known. 8 | 9 | 10 | .area _CODE 11 | .area _DATA 12 | .globl _main 13 | 14 | ; Two functions from Mailstation codeflash ROM are required, a delay 15 | ; and the set LED function. Both of these take an argument that has 16 | ; been pushed on to the stack prior to calling. 17 | 18 | ; Delay time is in milliseconds(?), value pushed on to the stack. 19 | delay = 0x0A5C 20 | ; LED value is 0 or 1, value pushed on to the stack. 21 | setled = 0x0A77 22 | 23 | _main: 24 | ld de, #0h0000 25 | 26 | loop: 27 | 28 | ; Every loop, XOR e against 0x01 and push on to stack 29 | ld a, e 30 | xor #0x01 31 | ld e, a 32 | push de 33 | call setled 34 | pop de 35 | 36 | ; Delay for roughly 1 s 37 | ld hl, #0d1000 38 | push hl 39 | call delay 40 | pop hl 41 | 42 | jr loop 43 | -------------------------------------------------------------------------------- /codeflash_ROMs/gen_disasm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # SPDX-License-Identifier: BSD-2-Clause 4 | 5 | # This script will take the first file with the name "*codeflash*.bin" in each 6 | # subdirectory, split it in to 16 KiB pages, and disassemble each page using 7 | # z80dasm. 8 | # Aside from the first page of CF, which is hardwired to 0x0000 base, all of the 9 | # other CF pages should only ever be mapped to 0x4000 base, aka slot4000. 10 | 11 | # XXX Add check for z80dasm 12 | 13 | for DIR in */; do 14 | ( 15 | cd "${DIR}" || exit 16 | mkdir disasm 17 | FILE=$(ls ./*codeflash*.bin | head -n 1) 18 | ( 19 | cd disasm 20 | split -d -b 16384 --additional-suffix .bin "../${FILE}" page 21 | ) 22 | echo "Disassembling $(basename ${FILE})" 23 | for I in $(seq -w 0 63); do 24 | #dd if="${FILE}" of=disasm/page"${I}".bin bs=16384 count=1 skip="${I}" 25 | echo -e "; vim: syntax=z8a" > disasm/page"${I}".s 26 | z80dasm -alt -g 0x4000 disasm/page"${I}".bin >> disasm/page"${I}".s >/dev/null 2>&1 27 | done 28 | echo -e "; vim: syntax=z8a" > disasm/page00.s 29 | z80dasm -alt -g 0x0 disasm/page00.bin >> disasm/page00.s >/dev/null 2>&1 30 | ) 31 | done 32 | -------------------------------------------------------------------------------- /src/demos/channels/README.md: -------------------------------------------------------------------------------- 1 | # Channels 2 | The official Mailstation apps were named "channels." These included such things as news headlines, TV channel listings, lotto numbers, weather, and horoscope. A Mailstation account could subscribe to up to 5 different channels (this is why the maximum number of apps is suspected to be 5) that would update when the user connected to exchange email. 3 | 4 | These apps were mostly just static images that displayed localized information rather than being something interactive. However, they have hooks in to the Mailstation OS that gives them a "standard" window decoration and the ability to sanely return to the main Mailstation menu. This concept warrants further investigation 5 | 6 | Contained in here are a number of channel snapshots that were taking from Mailstation's that had them installed. Originally dumped with tools from the [mailstation-tools project](https://github.com/jcs/mailstation-tools), these have been modified to be buildable again. 7 | 8 | These are intended to run as apps, so, starting from `0x4000` as origin. 9 | 10 | The tvlisting app is where most of the RE effort and notes are kept to better understand the Mailstation channel interface. 11 | -------------------------------------------------------------------------------- /src/tools/msemu_4to8_loader/msemu_4to8_loader.s: -------------------------------------------------------------------------------- 1 | .module loader 2 | .area _DATA 3 | .area _CODE 4 | 5 | .globl _main 6 | 7 | _main: 8 | jp copyfrom4000to8000 9 | 10 | .dw (icon) 11 | .dw (caption) 12 | .dw (unknown_value) 13 | 14 | unknown_value: 15 | .db #00 16 | 17 | ; These values are used to shift the interior screen location in official 18 | ; Mailstation app frameworks 19 | xpos: 20 | .dw #0000 21 | ypos: 22 | .dw #0000 23 | 24 | caption: 25 | .dw #0001 ; Unknown meaning 26 | .dw endcap-caption-6 ; Calculate caption length 27 | .dw #0006 ; Offset to first character 28 | .ascii "4to8load" ; The caption string 29 | endcap: 30 | 31 | icon: 32 | 33 | copyfrom4000to8000: 34 | ; The main loading for this is accomplished with ldir auto-looping 35 | ; de reg is the destination, hl is the source, and bc is the number 36 | ; of bytes to shovel from the source to the destination. 37 | ld de, #0x8000 ; Destination address 38 | ld hl, #binstart ; Source address 39 | ld bc, #0x4000 - (binstart - _main) 40 | 41 | ld a, #1 ; Load RAM page 1 in to slot8000 42 | out (#08),a 43 | out (#07),a 44 | 45 | ldir 46 | jp 0x8000 47 | 48 | 49 | binstart: 50 | -------------------------------------------------------------------------------- /src/demos/drawimage/makefile: -------------------------------------------------------------------------------- 1 | 2 | CC = sdcc 3 | CFLAGS = -mz80 4 | LDFLAGS = --no-std-crt0 --code-loc 0x8100 --data-loc 0x0000 5 | AS = sdasz80 6 | ASFLAGS = -lso 7 | 8 | # NOTE: sdcc has a gotcha that crt0.rel MUST be first file the command line 9 | # if passing --no-std-crt0 during linking phase, if crt0.rel is used, be sure 10 | # it is the first COMMON_OBJS. If that is not possible, then this makefile 11 | # needs to be modified to adjust OBJS creation 12 | COMMON_OBJS = 13 | LOCAL_OBJS = crt0-asm.rel graphicslcd.rel drawimage.rel 14 | 15 | 16 | COMMON_DIR = $(CURDIR)/../../common/ 17 | COMMON_OBJS := $(addprefix $(COMMON_DIR), $(COMMON_OBJS)) 18 | 19 | OBJS = $(LOCAL_OBJS) 20 | 21 | all: drawimage.bin 22 | 23 | $(COMMON_OBJS): 24 | @$(MAKE) $(notdir $@) -C $(COMMON_DIR) 25 | 26 | %.bin: %.ihx 27 | objcopy -Iihex -Obinary $< $@ 28 | 29 | %.rel: %.c 30 | $(CC) $(CFLAGS) -c $< 31 | 32 | %.rel: %.s 33 | $(AS) $(ASFLAGS) $< 34 | 35 | %.ihx: $(OBJS) 36 | $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) -o $@ 37 | 38 | # Clean the COMMON_DIR only if there are COMMON_OBJS used here 39 | clean: 40 | @$(if $(strip $(COMMON_OBJS)), @$(MAKE) clean -C $(COMMON_DIR),) 41 | rm -f *.rel *.ihx *.bin *.lk *.sym *.lst *.noi *.map *.asm 42 | -------------------------------------------------------------------------------- /src/tools/msloader/trampoline.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | /* Copyright (c) 2020 KBEmbedded */ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | extern uint8_t end_of_file; 10 | 11 | void main(void) { 12 | uint8_t cnt = 1; 13 | uint8_t slot4_dev, slot4_page; 14 | uint8_t *stage2_start = &end_of_file; 15 | 16 | /* Save the current slot 4 setup. Its guaranteed to be DEV_DF 17 | * (at least it should always be, if not, something is wrong), 18 | * but the page will be variable. Repurpose slot 4 with RAM, 19 | * to be safe, we'll take the current slot8 page +1. In most 20 | * situations, it will be RAMp01 because RAMp00 is static slotC. 21 | */ 22 | slot4_dev = SLOT4_DEV; 23 | slot4_page = SLOT4_PAGE; 24 | 25 | SLOT4_DEV = DEV_RAM; 26 | SLOT4_PAGE = SLOT8_PAGE + 1; 27 | 28 | /* NOTE: The correct way to do this would be to copy 0x4000 - 29 | * bytes, however, since end_of_file is an extern, 30 | * sdcc kind of freaks out and doesn't emit LDIR opcodes and instead 31 | * ends up doing a very complex copy. In any case, it works, its just 32 | * ugly. There is probably a better way of doing this that I'm not 33 | * aware of. 34 | */ 35 | memcpy((uint8_t *)0x4000, stage2_start, 0x4000); 36 | __asm__ ("jp 0x4000"); 37 | } 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2019, KBEmbedded 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /src/tools/msloader/parport_method.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | /* Copyright (c) 2020 KBEmbedded */ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | /* mslib headers */ 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "interface.h" 15 | #include "msloader.h" 16 | #include "parport_method.h" 17 | 18 | /* Set up function pointers fot selecting which parport method to use */ 19 | uint16_t (*parport_read_ptr)(void) = &msfw_parport_read_byte; 20 | uint16_t (*parport_write_ptr)(uint8_t) = &msfw_parport_write_byte; 21 | 22 | const struct opt_tbl parport_opts[] = { 23 | { " Use msfw parallel port method (tribbles) [default]\n", sel_parport_msfw }, 24 | { " Use WiFiStation parallel port method (bytes)\n", sel_parport_wifi }, 25 | { NULL, NULL }, 26 | }; 27 | 28 | void sel_parport_msfw(void) 29 | { 30 | //XXX: May need to change parport ctrl line states here? 31 | parport_read_ptr = &msfw_parport_read_byte; 32 | parport_write_ptr = &msfw_parport_write_byte; 33 | go_to_main(); 34 | } 35 | 36 | void sel_parport_wifi(void) 37 | { 38 | parport_read_ptr = &wifi_parport_read_byte; 39 | parport_write_ptr = &wifi_parport_write_byte; 40 | go_to_main(); 41 | } 42 | 43 | void sel_parport(void) 44 | { 45 | cur_opts = parport_opts; 46 | draw_header(); 47 | draw_options(); 48 | } 49 | -------------------------------------------------------------------------------- /src/demos/drawimage/graphicslcd.s: -------------------------------------------------------------------------------- 1 | 2 | .globl _p2shadow 3 | 4 | ;///////////////////////////////////////////////// 5 | ;// This is essentially the same function as in 6 | ;// the Mailstation firmware, just removed so 7 | ;// that it can be accessed regardless of which 8 | ;// firmware version is used (since the address 9 | ;// changes). It draws the buffer at 0xc010 to 10 | ;// the LCD. 11 | ;// 12 | ;// If you never plan to use it, comment it out 13 | ;// to save some space. 14 | ;// 15 | ;///////////////////////////////////////////////// 16 | 17 | _UpdateGraphicsLCD:: 18 | push af 19 | push bc 20 | push de 21 | push hl 22 | 23 | in a, (#06) 24 | ld e, a 25 | push de 26 | ld a, #0x02 27 | out (#06), a 28 | ld hl, #0xc010 29 | call update_half 30 | ld a, #0x04 31 | out (#06), a 32 | ld hl, #0xca10 33 | call update_half 34 | pop de 35 | ld a, e 36 | out (#06), a 37 | 38 | pop hl 39 | pop de 40 | pop bc 41 | pop af 42 | ret 43 | 44 | update_half: 45 | ld b, #0x14 46 | update_half2: 47 | ld de, #0x4038 48 | 49 | push hl 50 | ld hl, (_p2shadow) 51 | ld a, (hl) 52 | and #0xF7 53 | ld (hl),a 54 | out (#02),a 55 | 56 | ld a, b 57 | dec a 58 | ld (de), a 59 | 60 | ld a, (hl) 61 | or #0x08 62 | ld (hl),a 63 | out (#02),a 64 | pop hl 65 | 66 | ld a, b 67 | ld b, #0x00 68 | ld c, #0x80 69 | ldir 70 | ld b,a 71 | djnz update_half2 72 | ret 73 | 74 | 75 | -------------------------------------------------------------------------------- /src/demos/FyOS/v0.01/scancode_table.inc: -------------------------------------------------------------------------------- 1 | 2 | ; lowercase 3 | .db #0d000, #0d000, #0d000, #0d000, #0d000, #0d000, #0d000, #0d000 4 | .db #0d255, #0d255, #0d255, #0d064, #0d000, #0d000, #0d000, #0d000 5 | .db #0d096, #0d049, #0d050, #0d051, #0d052, #0d053, #0d054, #0d055 6 | .db #0d056, #0d057, #0d048, #0d045, #0d061, #0d008, #0d092, #0d000 7 | .db #0d009, #0d113, #0d119, #0d101, #0d114, #0d116, #0d121, #0d117 8 | .db #0d105, #0d111, #0d112, #0d091, #0d093, #0d059, #0d039, #0d013 9 | .db #0d255, #0d097, #0d115, #0d100, #0d102, #0d103, #0d104, #0d106 10 | .db #0d107, #0d108, #0d044, #0d046, #0d047, #0d000, #0d000, #0d000 11 | .db #0d255, #0d122, #0d120, #0d099, #0d118, #0d098, #0d110, #0d109 12 | .db #0d255, #0d255, #0d255, #0d032, #0d255, #0d255, #0d255, #0d000 13 | ; uppercase 14 | .db #0d000, #0d000, #0d000, #0d000, #0d000, #0d000, #0d000, #0d000 15 | .db #0d255, #0d255, #0d255, #0d064, #0d000, #0d000, #0d000, #0d000 16 | .db #0d126, #0d033, #0d064, #0d035, #0d036, #0d037, #0d094, #0d038 17 | .db #0d042, #0d040, #0d041, #0d095, #0d043, #0d008, #0d124, #0d000 18 | .db #0d009, #0d081, #0d087, #0d069, #0d082, #0d084, #0d089, #0d085 19 | .db #0d073, #0d079, #0d080, #0d123, #0d125, #0d058, #0d034, #0d013 20 | .db #0d255, #0d065, #0d083, #0d068, #0d070, #0d071, #0d072, #0d074 21 | .db #0d075, #0d076, #0d060, #0d062, #0d063, #0d000, #0d000, #0d000 22 | .db #0d255, #0d090, #0d088, #0d067, #0d086, #0d066, #0d078, #0d077 23 | .db #0d255, #0d255, #0d255, #0d032, #0d255, #0d255, #0d255, #0d000 24 | 25 | -------------------------------------------------------------------------------- /src/demos/FyOS/v0.02/scancode_table.inc: -------------------------------------------------------------------------------- 1 | 2 | ; lowercase 3 | .db #0d000, #0d000, #0d000, #0d000, #0d000, #0d000, #0d000, #0d000 4 | .db #0d255, #0d255, #0d255, #0d064, #0d000, #0d000, #0d000, #0d000 5 | .db #0d096, #0d049, #0d050, #0d051, #0d052, #0d053, #0d054, #0d055 6 | .db #0d056, #0d057, #0d048, #0d045, #0d061, #0d008, #0d092, #0d000 7 | .db #0d009, #0d113, #0d119, #0d101, #0d114, #0d116, #0d121, #0d117 8 | .db #0d105, #0d111, #0d112, #0d091, #0d093, #0d059, #0d039, #0d013 9 | .db #0d255, #0d097, #0d115, #0d100, #0d102, #0d103, #0d104, #0d106 10 | .db #0d107, #0d108, #0d044, #0d046, #0d047, #0d000, #0d000, #0d000 11 | .db #0d255, #0d122, #0d120, #0d099, #0d118, #0d098, #0d110, #0d109 12 | .db #0d255, #0d255, #0d255, #0d032, #0d255, #0d255, #0d255, #0d000 13 | ; uppercase 14 | .db #0d000, #0d000, #0d000, #0d000, #0d000, #0d000, #0d000, #0d000 15 | .db #0d255, #0d255, #0d255, #0d064, #0d000, #0d000, #0d000, #0d000 16 | .db #0d126, #0d033, #0d064, #0d035, #0d036, #0d037, #0d094, #0d038 17 | .db #0d042, #0d040, #0d041, #0d095, #0d043, #0d008, #0d124, #0d000 18 | .db #0d009, #0d081, #0d087, #0d069, #0d082, #0d084, #0d089, #0d085 19 | .db #0d073, #0d079, #0d080, #0d123, #0d125, #0d058, #0d034, #0d013 20 | .db #0d255, #0d065, #0d083, #0d068, #0d070, #0d071, #0d072, #0d074 21 | .db #0d075, #0d076, #0d060, #0d062, #0d063, #0d000, #0d000, #0d000 22 | .db #0d255, #0d090, #0d088, #0d067, #0d086, #0d066, #0d078, #0d077 23 | .db #0d255, #0d255, #0d255, #0d032, #0d255, #0d255, #0d255, #0d000 24 | 25 | -------------------------------------------------------------------------------- /src/tools/msloader/interface.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | /* Copyright (c) 2020 KBEmbedded */ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | /* mslib headers */ 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "interface.h" 17 | #include "parport_method.h" 18 | 19 | 20 | const struct opt_tbl *cur_opts; 21 | uint8_t line; 22 | uint8_t line_max; 23 | 24 | void draw_header(void) 25 | { 26 | g_textmode_init(); 27 | g_textmode_set_ypos(1); 28 | g_textmode_set_xpos(24); 29 | g_textmode_set_invert(1); 30 | g_textmode_clear_line(0); 31 | g_textmode_clear_line(1); 32 | g_textmode_clear_line(2); 33 | printf("Mailstation Loader Utility v0.24\n\n"); 34 | g_textmode_set_invert(0); 35 | g_textmode_set_ypos(17); 36 | printf("Parallel port method is set to: %s\n", parport_read_ptr == \ 37 | &msfw_parport_read_byte ? "msfw method" : "WiFiStation method"); 38 | g_textmode_set_ypos(19); 39 | printf("Navigate with \'h\' \'j\' \'k\' and \'l\'\n"); 40 | } 41 | 42 | void draw_options(void) 43 | { 44 | uint8_t i; 45 | 46 | g_textmode_set_ypos(4); 47 | for (i = 0; cur_opts[i].string != NULL; i++) { 48 | /* This printf, since not a static string, includes a lot 49 | * of overhead in the sdcc library to support it */ 50 | printf(cur_opts[i].string); 51 | } 52 | g_textmode_invert_line(4); 53 | line = 4; 54 | line_max = i + 3; 55 | } 56 | -------------------------------------------------------------------------------- /src/mslib/lcd.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | /* Copyright (c) 2020 KBEmbedded */ 3 | 4 | #include 5 | #include 6 | 7 | #include "ms_ports.h" 8 | 9 | void lcd_buf_clr(void) 10 | { 11 | memset((uint8_t *)0xC010, 0x00, 0x1400); 12 | } 13 | 14 | /* Update 0xA00 bytes of LCD screen from RAM buffer 15 | * 16 | * Based on MS firmware code. This updates half of the LCD starting from buf 17 | * for 0xA00 bytes. 18 | * 19 | * This function expects to have the correct LCD half already set in slot8 20 | */ 21 | static void lcd_update_half(uint8_t *buf) 22 | { 23 | volatile uint8_t *row_addr = (uint8_t *)0x8038; 24 | uint8_t col_addr = 0x14; 25 | 26 | do { 27 | /* HACK! Disable interrupts while we do this since MS ISR 28 | * wants to use a shadow register for P2! */ 29 | __asm__ ("di"); 30 | MISC2 &= ~MISC2_LCD_CASn; 31 | *row_addr = (--col_addr); 32 | MISC2 |= MISC2_LCD_CASn; 33 | __asm__ ("ei"); 34 | 35 | memcpy(row_addr, buf, 0x80); 36 | 37 | buf += 0x80; 38 | } while (col_addr); 39 | 40 | } 41 | 42 | 43 | /* Update LCD display from RAM buffer starting at 0xC010 44 | * 45 | * Based on the MS firmware code which exists in different ROM locations on 46 | * different firmware revisions. As the LCD is two separate devices, each half 47 | * of the LCD needs to be updated separately from different offsets in the 48 | * buffer. The buffer address is the same as the MS firmware. 49 | * 50 | * This function will set and restore slot8 device. 51 | */ 52 | void lcd_update(void) 53 | { 54 | uint8_t slot8_dev; 55 | 56 | slot8_dev = SLOT8_DEV; 57 | 58 | SLOT8_DEV = DEV_LCD_L; 59 | lcd_update_half((uint8_t *)0xC010); 60 | SLOT8_DEV = DEV_LCD_R; 61 | lcd_update_half((uint8_t *)0xCA10); 62 | 63 | SLOT8_DEV = slot8_dev; 64 | } 65 | -------------------------------------------------------------------------------- /src/demos/FyOS/v0.01/mailstation.h: -------------------------------------------------------------------------------- 1 | #ifndef _INCL_MAILSTATION 2 | #define _INCL_MAILSTATION 3 | 4 | // External variables defined in assembly code 5 | extern volatile unsigned char textmodebuffer[640]; 6 | extern volatile unsigned char cursorx; 7 | extern volatile unsigned char cursory; 8 | extern unsigned char *cgafont_addr; 9 | extern unsigned char *p2shadow; 10 | extern unsigned char *p3shadow; 11 | extern unsigned char firmwareversionsafe; 12 | 13 | 14 | // Define some pointers for page4000 addressing 15 | volatile unsigned char __at 0x4000 mem4000; 16 | //unsigned char *pmem4000 = &mem4000; 17 | 18 | // Define some ports 19 | __sfr __at 0x02 port2; 20 | __sfr __at 0x05 slot4000page; 21 | __sfr __at 0x06 slot4000device; 22 | __sfr __at 0x07 slot8000page; 23 | __sfr __at 0x08 slot8000device; 24 | 25 | // Define some device IDs 26 | #define device_codeflash 0x00 // 64 pages 27 | #define device_ram 0x01 // 08 pages 28 | #define device_LCD_left 0x02 // 01 pages 29 | #define device_dataflash 0x03 // 32 pages 30 | #define device_LCD_right 0x04 // 01 pages 31 | #define device_modem 0x05 // 01 pages 32 | 33 | 34 | 35 | // Define some functions 36 | void powerdownmode(); 37 | void LCD_CAS_C(unsigned char casbit); 38 | void clrscr(); 39 | //unsigned char getch(); 40 | //unsigned char getscancode(); 41 | void putcharXY(unsigned char x, unsigned char y, unsigned char c); 42 | void printfXY(unsigned char x, unsigned char y, char *xystring, ...); 43 | void printfcenter(char *centerstring, ...); 44 | int hex_nibble (char x) ; 45 | char hextoint(char *hexstring, unsigned int *hexint); 46 | char hextobyte(char *hexstring, unsigned char *hexbyte); 47 | char *gets(char *s); 48 | char isupper(char upperchar); 49 | char tolower(char upperchar); 50 | void strtolower(char *upperstring); 51 | 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /src/tools/msloader/msloader-app_info.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | /* Copyright (c) 2020 KBEmbedded */ 3 | 4 | #include "dflash_app.h" 5 | 6 | const dataflash_name app_name = { 7 | 0x0001, 8 | 9, 9 | 0x0006, 10 | "MS Loader" 11 | }; 12 | 13 | // Automatically generated by scripts/icon_bmp_to_struct_init.sh 14 | const dataflash_icon_no_icon1 app_icon = { 15 | 0xAD, 16 | 0x8, 17 | 0x0, 18 | 0x0, 19 | 0x22, 20 | 0x22, 21 | { 22 | { 0x00, 0x00, 0x00, 0x00, 0x00 }, 23 | { 0x00, 0x00, 0x00, 0x00, 0x00 }, 24 | { 0x00, 0x01, 0x3A, 0x00, 0x00 }, 25 | { 0x80, 0x01, 0x2B, 0x00, 0x00 }, 26 | { 0x00, 0x21, 0x2A, 0x70, 0x00 }, 27 | { 0x00, 0x31, 0x2A, 0x51, 0x00 }, 28 | { 0x38, 0x21, 0xBA, 0x51, 0x00 }, 29 | { 0x28, 0x20, 0x00, 0x51, 0x00 }, 30 | { 0x28, 0x20, 0x00, 0x71, 0x00 }, 31 | { 0x28, 0x00, 0x00, 0x01, 0x00 }, 32 | { 0x38, 0x00, 0x00, 0x00, 0x00 }, 33 | { 0x00, 0x00, 0x00, 0x00, 0x00 }, 34 | { 0xF8, 0xFF, 0xFF, 0x3F, 0x00 }, 35 | { 0x0C, 0x00, 0x00, 0x60, 0x00 }, 36 | { 0x04, 0x00, 0x00, 0x40, 0x00 }, 37 | { 0x54, 0x55, 0x55, 0x55, 0x00 }, 38 | { 0x0C, 0x00, 0x00, 0x60, 0x00 }, 39 | { 0xA8, 0xAA, 0xAA, 0x2A, 0x00 }, 40 | { 0x18, 0x00, 0x00, 0x30, 0x00 }, 41 | { 0x10, 0x00, 0x00, 0x10, 0x00 }, 42 | { 0xF0, 0xFF, 0xFF, 0x1F, 0x00 }, 43 | { 0x00, 0x00, 0x00, 0x00, 0x00 }, 44 | { 0x00, 0x00, 0xC0, 0x01, 0x00 }, 45 | { 0x08, 0xE0, 0x40, 0x01, 0x00 }, 46 | { 0x0C, 0xA0, 0x40, 0x1D, 0x00 }, 47 | { 0x08, 0xA0, 0x40, 0x15, 0x00 }, 48 | { 0x08, 0xA0, 0xC0, 0x15, 0x00 }, 49 | { 0x08, 0xE8, 0x00, 0x14, 0x00 }, 50 | { 0xC0, 0x0D, 0x1C, 0x1C, 0x00 }, 51 | { 0x40, 0x09, 0x14, 0x00, 0x00 }, 52 | { 0x40, 0x09, 0x14, 0x00, 0x00 }, 53 | { 0x40, 0x09, 0x14, 0x00, 0x00 }, 54 | { 0xC0, 0x01, 0x1C, 0x00, 0x00 }, 55 | { 0x00, 0x00, 0x00, 0x00, 0x00 }, 56 | } 57 | }; 58 | -------------------------------------------------------------------------------- /scripts/icon_bmp_to_struct_init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # SPDX-License-Identifier: BSD-2-Clause 4 | # Copyright (c) 2020 KBEmbedded 5 | 6 | # Convert a monochrome BMP file to an init that is suitable for use 7 | # in a header file. 8 | # 9 | # Icons are only 34x34, but requires a 40x34 source so it is byte aligned 10 | # 11 | # Usage: 12 | # icon_bmp_to_struct_init.sh 13 | 14 | if [ $# -ne 1 ]; then 15 | echo "Usage:" 16 | echo " ${0} " 17 | echo "" 18 | exit 1 19 | fi 20 | 21 | if [ ! -x "$(command -v convert)" ]; then 22 | echo "Error: convert is not available (is Imagemagick installed?)" 23 | exit 1 24 | fi 25 | 26 | FILENAME=$(basename -- "${1}") 27 | FILENAME="${FILENAME%.*}" 28 | 29 | convert "${1}" -monochrome MONO:"${FILENAME}".bin 30 | 31 | # Build a .h and populate it with default struct/members for app icon 32 | rm "${FILENAME}".h 2>/dev/null 33 | echo "// Automatically generated by scripts/$(basename -- "${0}")" >> "${FILENAME}".h 34 | echo "const dataflash_icon_no_icon1 app_icon = {" >> "${FILENAME}".h 35 | 36 | # See src/include/dflash_app.h for information on these values 37 | echo -e "\\t0xAD," >> "${FILENAME}".h # icon0 size 38 | echo -e "\\t0x8," >> "${FILENAME}".h # icon0 start 39 | echo -e "\\t0x0," >> "${FILENAME}".h # icon1 size (unused) 40 | echo -e "\\t0x0," >> "${FILENAME}".h # icon1 start (unused) 41 | echo -e "\\t0x22," >> "${FILENAME}".h # icon0 width (should be 34 px) 42 | echo -e "\\t0x22," >> "${FILENAME}".h # icon0 height (should be 34 px) 43 | echo -e "\\t{" >> "${FILENAME}".h 44 | 45 | # Now need to write the 40x34 px binary array here in 8-bit bytes 46 | hexdump -v -e'"\t{ "' -e' 4/1 "0x%02X, " 1/1 " 0x%02X },\n"' "${FILENAME}".bin >> "${FILENAME}".h 47 | echo -e "\\t}" >> "${FILENAME}".h 48 | echo -e "};" >> "${FILENAME}".h 49 | 50 | rm "${FILENAME}".bin 2>/dev/null 51 | -------------------------------------------------------------------------------- /src/tools/msloader/makefile: -------------------------------------------------------------------------------- 1 | 2 | INCLUDES = -I$(CURDIR)/../../include/ 3 | CC = sdcc 4 | CFLAGS = $(INCLUDES) -mz80 5 | LDFLAGS = --no-std-crt0 6 | AS = sdasz80 7 | ASFLAGS = -lso 8 | ASFLAGS_CRT0 := $(ASFLAGS) -g 9 | 10 | MSLIB_DIR = $(CURDIR)/../../mslib 11 | 12 | .PHONY: all LDR.out clean 13 | 14 | all: msloader.bin msloader-LDR.bin LDR.out 15 | 16 | $(MSLIB_DIR)/%.lib: 17 | @$(MAKE) $(notdir $@) -C $(MSLIB_DIR) 18 | 19 | $(MSLIB_DIR)/%.rel: 20 | @$(MAKE) $(notdir $@) -C $(MSLIB_DIR) 21 | 22 | trampoline.bin LDR.bin: %.bin: %.ihx 23 | objcopy -Iihex -Obinary $< $@ 24 | xxd -i $@ | sed -e 's/unsigned char/const uint8_t/' -e 's/unsigned int/const uint16_t/' > $@.h 25 | 26 | msloader-LDR.bin: msloader.bin trampoline.bin 27 | cat trampoline.bin msloader.bin > msloader-LDR.bin 28 | 29 | LDR.out: | LDR.bin 30 | @echo "\nWrite the following bytes to the Mailstation App location" 31 | @hexdump -e '8/1 "%02x " " " 8/1 "%02x " "\n"' LDR.bin 32 | @echo "" 33 | 34 | %.bin: %.ihx 35 | objcopy -Iihex -Obinary $< $@ 36 | 37 | %.rel: %.c 38 | $(CC) $(CFLAGS) -c $< 39 | 40 | 41 | dump.rel: dump.c | trampoline.bin LDR.bin 42 | $(CC) $(CFLAGS) -c $< 43 | 44 | %.rel: %.s 45 | $(AS) $(ASFLAGS) $< 46 | 47 | # crt0 sources need to be assembled with -g 48 | crt0%rel: crt0%s 49 | $(AS) $(ASFLAGS_CRT0) $< 50 | 51 | msloader.ihx: $(MSLIB_DIR)/crt0-slot4.rel $(MSLIB_DIR)/mslib.lib msloader.rel save.rel dump.rel loadrun.rel parport_method.rel interface.rel 52 | $(CC) $(CFLAGS) $(LDFLAGS) --code-loc 0x401A --data-loc 0xF000 $^ -o $@ 53 | 54 | trampoline.ihx: crt0-msloader-LDR.rel trampoline.rel 55 | $(CC) $(CFLAGS) $(LDFLAGS) --code-loc 0x8016 --data-loc 0xF000 $^ -o $@ 56 | 57 | LDR.ihx: LDR.rel 58 | $(CC) $(CFLAGS) $(LDFLAGS) --code-loc 0x4000 --data-loc 0x4000 $< -o $@ 59 | 60 | clean: 61 | @$(MAKE) clean -C $(MSLIB_DIR) 62 | rm -f *.rel *.ihx *.bin *.lk *.sym *.lst *.noi *.map *.asm *.bin.h 63 | -------------------------------------------------------------------------------- /src/demos/drawimage/drawimage.s: -------------------------------------------------------------------------------- 1 | ; SPDX-License-Identifier: BSD-2-Clause 2 | 3 | ; Quick demo demonstrating drawing to the screen using a raw binary as 4 | ; well as a custom RLE encoding scheme. Uses a graphics drawing routine 5 | ; that was pulled from Mailstation codeflash and copied here 6 | ; Comment the line called out below in order to display the RLE image, 7 | ; otherwise defaults to drawing a cityscape image. 8 | 9 | ; Originally written by FyberOptic 10 | 11 | .globl _p2shadow 12 | .globl _UpdateGraphicsLCD 13 | 14 | .area _CODE 15 | 16 | _main:: 17 | 18 | di 19 | 20 | ld hl, #cityscape 21 | ld de, #0xc010 22 | ld bc, #0d5120 ; #002$ - #001$ 23 | ldir 24 | call _UpdateGraphicsLCD 25 | 26 | ; Comment the following line to draw RLE Fybertech logo 27 | jp . 28 | 29 | ;---- 30 | 31 | ld ix, #logodata ; ix = rle data 32 | ld hl, #0xc010 ; hl = destination for decompression 33 | 34 | decodenext: 35 | ld b, #0 ; load # of repeating bytes into bc counter 36 | ld c, (ix) 37 | 38 | inc ix 39 | 40 | ld a, (ix) ; a = byte to repeat 41 | ld d, a ; preserve a 42 | 43 | or c 44 | jr z, decode_done ; check if a | c = 0. if so, rle_done 45 | 46 | ld a, d ; restore a 47 | ;ld a, #0d255 48 | ld (hl), a ; load byte value into mem location 49 | 50 | dec bc ; count minus one 51 | 52 | xor a ; if count was just 1, skip ldir sequence, since we already put one byte 53 | or c 54 | jr z, singlebytedecode 55 | 56 | ld d, h ; de = hl 57 | ld e, l 58 | inc de ; + 1 59 | 60 | ldir ; repeat character into memory 61 | 62 | singlebytedecode: 63 | inc hl ; increment memory location 64 | inc ix ; put ix at next data byte 65 | 66 | jr decodenext ; decode more 67 | 68 | 69 | decode_done: 70 | 71 | call _UpdateGraphicsLCD 72 | 73 | ;ld hl, #_p2shadow 74 | ;ld a, (hl) 75 | ;set 4, a 76 | ;ld (hl), a 77 | ;out (#02), a 78 | 79 | jr . 80 | 81 | 82 | 83 | .area _DATA 84 | logodata: 85 | .include "fybertechlogo_rle.inc" 86 | cityscape: 87 | .include "cityscape.inc" 88 | -------------------------------------------------------------------------------- /src/demos/FyOS/v0.02/mailstation.h: -------------------------------------------------------------------------------- 1 | #ifndef _INCL_MAILSTATION 2 | #define _INCL_MAILSTATION 3 | 4 | // External variables defined in assembly code 5 | extern volatile unsigned char textmodebuffer[640]; 6 | extern volatile unsigned char cursorx; 7 | extern volatile unsigned char cursory; 8 | extern unsigned char *cgafont_addr; 9 | extern unsigned char *p2shadow; 10 | extern unsigned char *p3shadow; 11 | extern unsigned char firmwareversionsafe; 12 | 13 | // Pointer to the graphical LCD buffer, if wanted (5120 bytes) 14 | //volatile unsigned char *graphicsmodebuffer = (unsigned char *)0xC010; 15 | 16 | // Pointers for easy page4000 addressing 17 | volatile unsigned char __at 0x4000 mem4000; 18 | //unsigned char *pmem4000 = &mem4000; 19 | 20 | 21 | 22 | // Define some ports 23 | __sfr __at 0x02 port2; 24 | __sfr __at 0x05 slot4000page; 25 | __sfr __at 0x06 slot4000device; 26 | __sfr __at 0x07 slot8000page; 27 | __sfr __at 0x08 slot8000device; 28 | 29 | // Define some device IDs 30 | #define device_codeflash 0x00 // 64 pages 31 | #define device_ram 0x01 // 08 pages 32 | #define device_LCD_left 0x02 // 01 pages 33 | #define device_dataflash 0x03 // 32 pages 34 | #define device_LCD_right 0x04 // 01 pages 35 | #define device_modem 0x05 // 01 pages 36 | 37 | 38 | 39 | // Define some functions. These are described in mailstation.c. 40 | void powerdownmode(); 41 | void clrscr(); 42 | unsigned char getscancode(unsigned char *charbuffer); 43 | void putcharXY(unsigned char x, unsigned char y, unsigned char c); 44 | void printfXY(unsigned char x, unsigned char y, char *xystring, ...); 45 | void printfcenter(char *centerstring, ...); 46 | int hex_nibble (char x) ; 47 | char hextoint(char *hexstring, unsigned int *hexint); 48 | char hextobyte(char *hexstring, unsigned char *hexbyte); 49 | char *gets(char *s); 50 | char isupper(char upperchar); 51 | char tolower(char upperchar); 52 | void strtolower(char *upperstring); 53 | void UpdateGraphicsLCD() __naked; 54 | 55 | // External functions, described in putchar.s 56 | extern void LCD_CAS(char); 57 | extern void ClearLCD(); 58 | extern void scrollscreen(); 59 | extern void UpdateCharLCD(); 60 | 61 | 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /src/mslib/keyboard.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | /* Copyright (c) 2021 KBEmbedded */ 3 | 4 | #include 5 | #include 6 | 7 | /* This lookup table is whatever right now */ 8 | const char scode_lower[160] = { 9 | /* Main Back Print F1 F2 F3 F4 F5 */ 10 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 11 | /* NULL NULL NULL @ Size Chk Spl Get Eml PgUp */ 12 | 0x00, 0x00, 0x00, '@', 0x00, 0x00, 0x00, 0x00, 13 | /* ` 1 2 3 4 5 6 7 */ 14 | '`', '1', '2', '3', '4', '5', '6', '7', 15 | /* 8 9 0 - = Del \ PgDn */ 16 | '8', '9', '0', '-', '=', 0x08, '\\', 0x00, 17 | /* Tab q w e r t y u */ 18 | 0x09, 'q', 'w', 'e', 'r', 't', 'y', 'u', 19 | /* i o p [ ] ; ' Enter */ 20 | 'i', 'o', 'p', '[', ']', ';', '\'', 0x0A, 21 | /* Caps a s d f g h j */ 22 | 0x00, 'a', 's', 'd', 'f', 'g', 'h', 'j', 23 | /* k l , . / UpAr DnAr RiAr */ 24 | 'k', 'l', ',', '.', '/', 0x00, 0x00, 0x00, 25 | /* LShift z x c v b n m */ 26 | 0x00, 'z', 'x', 'c', 'v', 'b', 'n', 'm', 27 | /* Fn NULL NULL Space NULL NULL RShift LeAr */ 28 | 0x00, 0x00, 0x00, ' ', 0x00, 0x00, 0x00, 0x00, 29 | 30 | /* Main Back Print F1 F2 F3 F4 F5 */ 31 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 32 | /* NULL NULL NULL @ Size Chk Spl Get Eml PgUp */ 33 | 0x00, 0x00, 0x00, '@', 0x00, 0x00, 0x00, 0x00, 34 | /* ` 1 2 3 4 5 6 7 */ 35 | '~', '!', '@', '#', '$', '%', '^', '&', 36 | /* 8 9 0 - = Del \ PgDn */ 37 | '*', '(', ')', '_', '+', 0x08, '|', 0x00, 38 | /* Tab q w e r t y u */ 39 | 0x09, 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 40 | /* i o p [ ] ; ' Enter */ 41 | 'I', 'O', 'P', '{', '}', ':', '\"', 0x0A, 42 | /* Caps a s d f g h j */ 43 | 0x00, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 44 | /* k l , . / UpAr DnAr RiAr */ 45 | 'K', 'L', '<', '>', '?', 0x00, 0x00, 0x00, 46 | /* LShift z x c v b n m */ 47 | 0x00, 'Z', 'X', 'C', 'V', 'B', 'N', 'M', 48 | /* Fn NULL NULL Space NULL NULL RShift LeAr */ 49 | 0x00, 0x00, 0x00, ' ', 0x00, 0x00, 0x00, 0x00, 50 | }; 51 | 52 | void kbd_flush(void) 53 | { 54 | uint8_t buf[2]; 55 | 56 | while(msfw_get_scancode(buf)); 57 | } 58 | 59 | void kbd_anykey(void) 60 | { 61 | uint8_t buf[2] = {0}; 62 | 63 | /* Loop getting keyboard scancodes until there is a valid button down event */ 64 | while (!msfw_get_scancode(buf) || !(buf[1] & 0x1)); 65 | } 66 | 67 | -------------------------------------------------------------------------------- /src/demos/drawimage/fybertechlogo_rle.inc: -------------------------------------------------------------------------------- 1 | 2 | .db #0xff, #0x00, #0xaf, #0x00, #0x23, #0xff, #0x5d, #0x00 3 | .db #0x05, #0xff, #0x0a, #0x01, #0x05, #0xff, #0x0f, #0x01 4 | .db #0x5d, #0x00, #0x05, #0xff, #0x0a, #0x00, #0x05, #0x0f 5 | .db #0x6c, #0x00, #0x05, #0x01, #0x26, #0x00, #0x04, #0xf0 6 | .db #0x59, #0x00, #0x18, #0xff, #0x03, #0xf0, #0x08, #0x00 7 | .db #0x04, #0xff, #0x59, #0x00, #0x17, #0x80, #0x04, #0xff 8 | .db #0x04, #0xf0, #0x05, #0xff, #0x03, #0x0f, #0x59, #0x00 9 | .db #0x18, #0xff, #0x08, #0x0f, #0x58, #0x00, #0x23, #0x80 10 | .db #0x5d, #0x00, #0x23, #0xff, #0x65, #0x00, #0x04, #0xff 11 | .db #0x13, #0x80, #0x04, #0xff, #0x65, #0x00, #0x04, #0x0f 12 | .db #0x14, #0xff, #0x03, #0x0f, #0x69, #0x00, #0x14, #0x80 13 | .db #0x68, #0x00, #0x04, #0xf8, #0x07, #0x7f, #0x05, #0xff 14 | .db #0x07, #0x7f, #0x01, #0xff, #0x04, #0xf8, #0x64, #0x00 15 | .db #0x04, #0xff, #0x07, #0xc0, #0x05, #0xff, #0x07, #0x00 16 | .db #0x05, #0xff, #0x64, #0x00, #0x04, #0x07, #0x0c, #0x7f 17 | .db #0x07, #0x00, #0x05, #0x07, #0x64, #0x00, #0x1c, #0xc0 18 | .db #0x64, #0x00, #0x07, #0x7f, #0x05, #0xff, #0x10, #0x7f 19 | .db #0x64, #0x00, #0x04, #0xc0, #0x03, #0xfc, #0x01, #0xff 20 | .db #0x04, #0x07, #0x74, #0x00, #0x08, #0x7f, #0x78, #0x00 21 | .db #0x04, #0xc0, #0x74, #0x00, #0x08, #0xfc, #0x04, #0xff 22 | .db #0x14, #0xfc, #0x03, #0xe0, #0x5d, #0x00, #0x08, #0x03 23 | .db #0x04, #0xff, #0x13, #0x03, #0x04, #0xff, #0x65, #0x00 24 | .db #0x04, #0x3f, #0x13, #0x00, #0x04, #0x3f, #0x69, #0x00 25 | .db #0x13, #0xe0, #0x69, #0x00, #0x04, #0xfe, #0x07, #0x3f 26 | .db #0x05, #0xff, #0x07, #0x3f, #0x04, #0xfe, #0x65, #0x00 27 | .db #0x04, #0xff, #0x07, #0xe0, #0x05, #0xff, #0x07, #0x00 28 | .db #0x04, #0xff, #0x65, #0x00, #0x04, #0x03, #0x0c, #0x1f 29 | .db #0x07, #0x00, #0x04, #0x01, #0x69, #0x00, #0x14, #0xe0 30 | .db #0x68, #0x00, #0x04, #0xfe, #0x13, #0x1f, #0x01, #0xff 31 | .db #0x03, #0xfe, #0x65, #0x00, #0x04, #0xff, #0x04, #0xf0 32 | .db #0x0b, #0x00, #0x04, #0xf0, #0x04, #0xff, #0x65, #0x00 33 | .db #0x04, #0x01, #0x04, #0x1f, #0x0b, #0x00, #0x05, #0x1f 34 | .db #0x03, #0x01, #0x5d, #0x00, #0x23, #0xf0, #0x5d, #0x00 35 | .db #0x08, #0x1f, #0x04, #0xff, #0x17, #0x1f, #0x65, #0x00 36 | .db #0x04, #0xff, #0x17, #0xf0, #0x65, #0x00, #0x03, #0x01 37 | .db #0x18, #0x0f, #0xff, #0x00, #0x30, #0x00, #0x00, #0x00 38 | -------------------------------------------------------------------------------- /src/tools/msemu_4to8_loader/README.md: -------------------------------------------------------------------------------- 1 | # MSEMU 4to8 loader 2 | 3 | A simple stub of a program designed for use with the msemu tool in lieu of parallel port loading. Since msemu doesn't support parallel port at this time, this tool is a bit of a workaround to add emulated support of the stage 0 loader. 4 | 5 | `meemu_4to8_loader` is assembled with an org of 0x4000 and is meant to have another binary appended to it. `msemu_4to8_loader` is then run as a dataflash application, the appended binary is loaded in to RAM page 1, set in to slot8, and then is blindly executed. This is similar to the behavior of the stage 0 loader, but can all be done from the emulated dataflash.bin in msemu. 6 | 7 | ## Use 8 | 9 | Note that this requires dataflash.bin set up to run an app from 0x0000, aka dataflash page 0, address 0. See the [Mailstation wiki](https://github.com/kbembedded/mailstation/wiki/Loading-Data-on-to-the-Mailstation) for information on how to set this up. Note that its possible to run `msemu_4to8_loader` from any app location, but the easiest way is to have it be the first application. Otherwise, the resulting binary will need to be placed somewhere in the middle of the dataflash.bin which results in a more complex dd command. 10 | 11 | ``` 12 | make 13 | cat /path/to/other.bin >> msemu_4to8_loader.bin 14 | dd if=msemu_4to8_loader.bin of=/path/to/msemu/dataflash.bin conv=notrunc 15 | ``` 16 | 17 | This can all be accomplished in a single line: 18 | 19 | `make bin=/path/to/other.bin df_out=/path/to/msemu/dataflash.bin` 20 | 21 | This will clean, rebuild, append the desired binary, and write it to the dataflash.bin file specified. 22 | Note that this will always write to offset 0 of the dataflash. This might not be what you want, but in most cases it will be. 23 | 24 | It is also possible to build the loader with the binary appended to it, this is useful if the resulting binary needs to be written to a custom location in dataflash. 25 | 26 | `make bin=/path/to/other.bin` 27 | 28 | This will output `msemu_4to8_loader-app.bin` with the loader and the binary appended together. 29 | 30 | 31 | # Bugs 32 | 33 | I doubt its a bug of this application, but in running "checksum" there is some garbage printed with the first line. The checksum values are off. In running FyOS v0.02 it IDs firmware 2.53 as 2.83 for some reason. That is also likely a fault of msemu and has nothing to do with this 34 | -------------------------------------------------------------------------------- /src/tools/msloader/crt0-msloader-LDR.s: -------------------------------------------------------------------------------- 1 | ; vim:syntax=z8a 2 | ; 3 | ; SPDX-License-Identifier: BSD-2-Clause 4 | ; Copyright (c) 2020 KBEmbedded 5 | ; 6 | ; Generalized crt0.s for Mailstation Apps running from slot8 7 | ; 8 | ; Based on SDCC z80 crt0.s and other Mailstation contributions 9 | 10 | 11 | .module crt0 12 | .globl _main 13 | 14 | .area _HEADER (ABS) 15 | 16 | ; Mailstation loader will put binary data starting at 0x8000, any tools 17 | ; compiled against this crt0 will be set up for that. 18 | .org 0x8000 19 | init: 20 | ; Set stack pointer directly above top of memory. 21 | ; Observations show this is pretty safe. 22 | ld sp,#0x0000 23 | 24 | ; preserve old slot4000 for later 25 | in a, (#06) 26 | ld (startup_slot4000device), a 27 | in a, (#05) 28 | ld (startup_slot4000page), a 29 | 30 | ; Initialise global variables 31 | call gsinit 32 | call _main 33 | jp _exit 34 | 35 | ;; Ordering of segments for the linker. 36 | .area _HOME 37 | .area _CODE 38 | .area _INITIALIZER 39 | .area _GSINIT 40 | .area _GSFINAL 41 | .area _AFTERCODE 42 | 43 | .area _DATA 44 | .area _INITIALIZED 45 | .area _BSEG 46 | 47 | .area _BSS 48 | ; Variables to save the currently mapped slot4 page, restore at exit 49 | ; and re-launch the loader since slot8 Apps should only be called 50 | ; from the loader 51 | startup_slot4000device: 52 | .ds 1 53 | startup_slot4000page: 54 | .ds 1 55 | 56 | .area _HEAP 57 | 58 | .area _CODE 59 | 60 | ; Unsure what clock does, but leave it in place in case it is called 61 | __clock:: 62 | ret 63 | 64 | _exit:: 65 | ; Exiting from mailstation app should jump back to the loader. Restore 66 | ; the original page to slot4000 and jump back to that. 67 | ; restore slot4000, jump to app 68 | ld a, (startup_slot4000device) 69 | out (#06),a 70 | ld a, (startup_slot4000page) 71 | out (#05),a 72 | jp 0x4000 73 | 74 | ; XXX: For some reason, sdcc 3.8.0 wants to put _GSINIT in data-loc. 75 | ; I've tried re-arranging sections, setting (CON) to all GSINIT 76 | ; areas, etc. For now, just letting this fall in to _CODE does 77 | ; what we want it to. 78 | ;.area _GSINIT 79 | gsinit:: 80 | ld bc, #l__INITIALIZER 81 | ld a, b 82 | or a, c 83 | jr Z, gsinit_next 84 | ld de, #s__INITIALIZED 85 | ld hl, #s__INITIALIZER 86 | ldir 87 | gsinit_next: 88 | 89 | ;.area _GSFINAL 90 | ret 91 | 92 | .area _AFTERCODE 93 | _end_of_file:: 94 | -------------------------------------------------------------------------------- /src/mslib/wifi_parport.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | /* Copyright (c) 2021 KBEmbedded */ 3 | 4 | /* Code derived from and intended to be compatible with jcs's WiFiStation: 5 | * Copyright (c) 2021 joshua stein 6 | * 7 | * Permission to use, copy, modify, and distribute this software for any 8 | * purpose with or without fee is hereby granted, provided that the above 9 | * copyright notice and this permission notice appear in all copies. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #include "CFfuncs.h" 24 | #include "ms_ports.h" 25 | 26 | /* XXX: This is necessary to do before using the wifistation method, 27 | * It may be possible to track down a CF func that does essentially this */ 28 | void wifi_parport_prepare(void) 29 | { 30 | /* Set all control lines low */ 31 | PAR_CTRL_DR &= ~(PAR_CTRL_MASK); 32 | PAR_CTRL_DDR |= PAR_CTRL_MASK; 33 | } 34 | 35 | /* Read a byte on parallel port */ 36 | /* Will timeout after 1s if no data received */ 37 | uint16_t wifi_parport_read_byte(void) 38 | { 39 | uint16_t ret; 40 | uint16_t cnt = 1000; 41 | 42 | wifi_parport_prepare(); 43 | 44 | /* Sender will raise busy when ready to send data */ 45 | while(!(PAR_STAT_DR & PAR_STAT_BUSYn)) { 46 | msfw_delay(1); 47 | cnt--; 48 | if(cnt == 0) return 0; 49 | } 50 | 51 | /* Set the data port as input */ 52 | PAR_DAT_DDR = 0x00; 53 | 54 | /* MS will raise autofeed/linefeed as ACK */ 55 | PAR_CTRL_DR |= PAR_CTRL_AUTFn; 56 | 57 | /* Wait for sender to lower busy when data is ready */ 58 | while(PAR_STAT_DR & PAR_STAT_BUSYn); 59 | 60 | /* Read data from sender */ 61 | ret = (uint16_t)PAR_DAT_DR; 62 | /* Set upper byte to 0xFF to mimic msfw_parport_read_byte setting 63 | * that byte as true if data is valid */ 64 | ret |= 0xFF00; 65 | 66 | /* Lower autofeed/linefeed to let sender know we've read data */ 67 | PAR_CTRL_DR &= ~(PAR_CTRL_AUTFn); 68 | 69 | return ret; 70 | } 71 | 72 | /* Looks like this will return 0 in the case of a timeout? */ 73 | uint16_t wifi_parport_write_byte(uint8_t val) 74 | { 75 | wifi_parport_prepare(); 76 | 77 | return (uint16_t)val; 78 | } 79 | -------------------------------------------------------------------------------- /src/include/ms_ports.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | /* Copyright (c) 2020 KBEmbedded */ 3 | 4 | #ifndef __MS_PORTS_H__ 5 | #define __MS_PORTS_H__ 6 | 7 | __sfr __at 0x01 KEYBOARD; 8 | __sfr __at 0x02 MISC2; 9 | __sfr __at 0x03 IRQ_MASK; 10 | __sfr __at 0x04 UNKNOWN0x4; 11 | __sfr __at 0x05 SLOT4_PAGE; 12 | __sfr __at 0x06 SLOT4_DEV; 13 | __sfr __at 0x07 SLOT8_PAGE; 14 | __sfr __at 0x08 SLOT8_DEV; 15 | __sfr __at 0x09 PAR_CTRL_DR; /* Printer ctrl, pwr ok, pwr btn, data reg */ 16 | __sfr __at 0x0A PAR_CTRL_DDR; /* Printer ctrl, pwr ok, pwr btn, data dir reg */ 17 | __sfr __at 0x0D OSC_CTRL; /* Controls CPU speed? */ 18 | __sfr __at 0x10 RTC_SEC; /* BCD, ones place seconds */ 19 | __sfr __at 0x11 RTC_10SEC; /* BCD, tens place seconds */ 20 | __sfr __at 0x12 RTC_MIN; /* BCD, ones place minutes */ 21 | __sfr __at 0x13 RTC_10MIN; /* BCD, tens place minutes */ 22 | __sfr __at 0x14 RTC_HR; /* BCD, ones place hours */ 23 | __sfr __at 0x15 RTC_10HR; /* BCD, tens place hours */ 24 | __sfr __at 0x16 RTC_DOW; /* BCD, day of week */ 25 | __sfr __at 0x17 RTC_DOM; /* BCD, ones place day of month */ 26 | __sfr __at 0x18 RTC_10DOM; /* BCD, tens place day of month */ 27 | __sfr __at 0x19 RTC_MON; /* BCD, ones place month */ 28 | __sfr __at 0x1A RTC_10MON; /* BCD, tens place month */ 29 | __sfr __at 0x1B RTC_YR; /* BCD, ones place years since 1980 */ 30 | __sfr __at 0x1C RTC_10YR; /* BCD, tens place years since 1980 */ 31 | __sfr __at 0x1D RTC_CTRL1; /* Unknown */ 32 | __sfr __at 0x1E RTC_CTRL2; /* Unknown */ 33 | __sfr __at 0x1F RTC_CTRL3; /* Unknown MSFW init sets this to 0xc*/ 34 | 35 | __sfr __at 0x21 PAR_STAT_DR; /* Parallel port status reg, input only */ 36 | __sfr __at 0x2C PAR_DAT_DDR; /* Parallel port data direction reg */ 37 | __sfr __at 0x2D PAR_DAT_DR; /* Parallel port data reg */ 38 | __sfr __at 0x2F TIMER_CTRL; /* Maybe? Group notes indicate this affects timer16 */ 39 | 40 | __sfr __at 0x24 UNKNOWN0x28; 41 | 42 | /* Devices that can be used in SLOTs */ 43 | #define DEV_CF 0x00 44 | #define DEV_RAM 0x01 45 | #define DEV_LCD_L 0x02 46 | #define DEV_DF 0x03 47 | #define DEV_LCD_R 0x04 48 | #define DEV_MODEM 0x05 49 | 50 | /* Parallel port defines/loc */ 51 | #define PAR_CTRL_STBn (1 << 0) // STROBE# 52 | #define PAR_CTRL_AUTFn (1 << 1) // AUTO_FEED#/LINEFEED# 53 | #define PAR_CTRL_RESET (1 << 2) // RESET 54 | #define PAR_CTRL_SELn (1 << 3) // SELECT_PRINTER# 55 | #define PAR_CTRL_MASK (0x0F) // Mask of all of the ctrl bits 56 | #define PAR_STAT_ERROR (1 << 3) // ERROR (input only) 57 | #define PAR_STAT_SEL (1 << 4) // SELECT 58 | #define PAR_STAT_POUT (1 << 5) // PAPER_OUT 59 | #define PAR_STAT_ACK (1 << 6) // ACK 60 | #define PAR_STAT_BUSYn (1 << 7) // BUSY 61 | 62 | #define MISC2_LCD_CASn (1 << 3) 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /src/mslib/msfw_parport.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | /* Copyright (c) 2020 KBEmbedded */ 3 | 4 | #include 5 | #include 6 | 7 | #include "ms_ports.h" 8 | 9 | /* Read a byte from the parallel port using tribbles. 10 | * 11 | * Returns 16-bits. The upper 8-bits, if non-zero, means the lower 8-bits are 12 | * a valid data byte read from the parallel port. If upper 8-bits are 0, then 13 | * there was a timeout on the parallel port. 14 | * 15 | * Written in assembly because of the calling convention necessary. This func 16 | * lives in CFp01, and normally is called when mapped to slot8. 17 | * 18 | * Calling the msfw function at 0x8027 will return a byte from the parport 19 | * in L register, with the A register being 0 if there was a timeout. 20 | * The __naked attribute means we need to handle saving registers, sdcc 21 | * generates no prologue/epilogue code. sdcc uses the HL register pair to 22 | * return 16-bits which is what already occurs, so this can just 23 | * ret at the end of it. The __naked attribute is what allows this to work 24 | * from C. 25 | * 26 | * NOTE: The MS firmware function uses some hard-coded RAM, 0xE3AC to store 27 | * temporary bytes. These functions might not be safe for all use. 28 | */ 29 | static uint16_t pp_rb_asm(void) __naked 30 | { 31 | __asm 32 | call 0x8027 ; Try to fetch a byte. 33 | ld h, a ; Put return flag in to upper byte 34 | ; the actual value is already set in L 35 | ret 36 | __endasm; 37 | } 38 | 39 | uint16_t msfw_parport_read_byte(void) 40 | { 41 | uint8_t slot8_dev, slot8_page; 42 | uint16_t ret; 43 | 44 | slot8_dev = SLOT8_DEV; 45 | slot8_page = SLOT8_PAGE; 46 | 47 | SLOT8_DEV = DEV_CF; 48 | SLOT8_PAGE = 0x01; 49 | 50 | ret = pp_rb_asm(); 51 | 52 | SLOT8_DEV = slot8_dev; 53 | SLOT8_PAGE = slot8_page; 54 | 55 | return ret; 56 | } 57 | 58 | static uint16_t pp_wb_asm(uint8_t val) __naked 59 | { 60 | __asm 61 | ld hl, #2 62 | add hl, sp 63 | ld a, (hl) 64 | ld h, a ; All of that to put sp+2 in 65 | ; to h 66 | call 0x802d ; Send byte to parport 67 | ld h, a ; Put return flag in to upper byte 68 | ; the actual value is already set in L 69 | ret 70 | __endasm; 71 | 72 | /* Reference the func arg in C to remove warnings about it */ 73 | val; 74 | } 75 | 76 | /* Looks like this will return 0 in the case of a timeout? */ 77 | uint16_t msfw_parport_write_byte(uint8_t val) 78 | { 79 | uint8_t slot8_dev, slot8_page; 80 | uint16_t ret; 81 | 82 | slot8_dev = SLOT8_DEV; 83 | slot8_page = SLOT8_PAGE; 84 | 85 | SLOT8_DEV = DEV_CF; 86 | SLOT8_PAGE = 0x01; 87 | 88 | ret = pp_wb_asm(val); 89 | 90 | SLOT8_DEV = slot8_dev; 91 | SLOT8_PAGE = slot8_page; 92 | 93 | return ret; 94 | } 95 | -------------------------------------------------------------------------------- /scripts/ttf_to_header.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # SPDX-License-Identifier: BSD-2-Clause 4 | # Copyright (c) 2020 KBEmbedded 5 | 6 | # Converts a TTF font file to a bitmap compatible with the Mailstation 7 | # Uses Imagemagick for the conversion process 8 | # 9 | # Note that this may not work quite right without tuning arguments to 'convert' 10 | # This script has only been used for the current fonts in this project 11 | # 12 | # Currently only generates standard ASCII symbols, the output include file only 13 | # ends up with printable characters, starting with space " " 14 | # 15 | # Usage: 16 | # ttf_to_header.sh 17 | 18 | if [ $# -ne 3 ]; then 19 | echo "Usage:" 20 | echo " ${0} " 21 | echo "" 22 | echo "This script might need tuning for some font files. Be sure" 23 | echo "to test each character as it would be printed on the Mailstation." 24 | echo "Additional development may be needed to add support for a new font size" 25 | echo "if it does not currently exist. Similar sized fonts may not be drop-in" 26 | echo "compatible with existing fonts." 27 | echo "" 28 | echo "Note! This script passes to Imagemagick a size that is 1 px wider than the" 29 | echo "actual font width. This is because Imagemagick seems to add an additional" 30 | echo "column (maybe kerning? I'm not sure) that causes weird truncation of chars." 31 | echo "This could be problematic with fonts greater than 7 bits wide, but, I doubt" 32 | echo "that such a font would look good on the MS anyway." 33 | exit 1 34 | fi 35 | 36 | if [ ! -x "$(command -v convert)" ]; then 37 | echo "Error: convert is not available (is Imagemagick installed?)" 38 | exit 1 39 | fi 40 | 41 | (( WIDTHMOD=${2}+1 )) 42 | OUTBIN=msfont_"${2}"x"${3}".bin 43 | OUTH=msfont_"${2}"x"${3}".h 44 | SIZE="${WIDTHMOD}"x"${3}" 45 | 46 | rm "${OUTBIN}" >/dev/null 2>&1 47 | 48 | for I in $(seq 32 126); do 49 | CHAR=$(printf "\x$(printf %x ${I})") 50 | if [ "${CHAR}" == "\\" ]; then CHAR="\\\\"; fi 51 | if [ "${CHAR}" == " " ]; then 52 | echo "HACK! The space character from TTF fonts ends up being all 1s rather than 0s." 53 | echo " Writing ${3} bytes to output in place of space. Note! This hack is a hack!" 54 | if [ "${2}" -gt 8 ]; then 55 | echo "Hack! Cannot handle the space character hack for fonts wider than 8 bits. Failing" 56 | exit 1; 57 | fi 58 | dd if=/dev/zero bs=1 count="${3}" of=label.bin >/dev/null 2>&1 59 | else 60 | convert -font "${1}" -size "${SIZE}" -pointsize "${3}" -gravity center label:"${CHAR}" -monochrome MONO:label.bin 61 | fi 62 | cat label.bin >> "${OUTBIN}" 63 | done 64 | 65 | rm label.bin 66 | rm "${OUTH}" >/dev/null 2>&1 67 | 68 | echo "#ifndef __MSFONT_${2}X${3}_H__" >> "${OUTH}" 69 | echo "#define __MSFONT_${2}X${3}_H__" >> "${OUTH}" 70 | 71 | xxd -i "${OUTBIN}" | sed -e 's/unsigned char/const uint8_t/' -e 's/unsigned int/const uint16_t/' >> "${OUTH}" 72 | 73 | echo "#endif //__MSFONT_${2}X${3}_H__" >> "${OUTH}" 74 | 75 | rm "${OUTBIN}" >/dev/null 2>&1 76 | -------------------------------------------------------------------------------- /src/mslib/crt0-slot4.s: -------------------------------------------------------------------------------- 1 | ; vim:syntax=z8a 2 | ; 3 | ; SPDX-License-Identifier: BSD-2-Clause 4 | ; Copyright (c) 2020 KBEmbedded 5 | ; 6 | ; Generalized crt0.s for Mailstation Apps running from slot4 7 | ; 8 | ; Based on SDCC z80 crt0.s and other Mailstation contributions 9 | 10 | 11 | .module crt0 12 | .globl _main 13 | 14 | .area _HEADER (ABS) 15 | 16 | ; Mailstation loader will put binary data starting at 0x4000, any tools 17 | ; compiled against this crt0 will be set up for that. 18 | .org 0x4000 19 | 20 | jp init 21 | 22 | ; When running an App/Channel from dataflash, there is a known header 23 | ; that supports having an icon, name, and some other data. Looks for 24 | ; global values in C that end up being the location of a struct with 25 | ; the necessary data. 26 | ; 27 | ; Its not the cleanest, and compiles fail if these globals arn't 28 | ; exported by something. But it works well enough and really only 29 | ; needs to be done once per tool. 30 | .dw (_app_icon) ; Start of the icon header 31 | .dw (_app_name) ; Start of the App name header 32 | .dw #0x0000 ; Start of data header with unknown function 33 | .db #0x00 ; Byte of unknown meaning 34 | .dw #0x0000 ; X position adjustment of Channel/icon1 35 | .dw #0x0000 ; Y position adjustment of Channel/icon1 36 | 37 | init: 38 | ; Set stack pointer directly above top of memory. 39 | ; Observations show this is pretty safe. 40 | ld sp, #0x0000 41 | 42 | ; Initialise global variables 43 | call gsinit 44 | call _main 45 | jp _exit 46 | 47 | ; Ordering of segments for the linker. 48 | 49 | ; Note that _HOME will likely end up falling in slotC, in there are 50 | ; a few areas of RAM we do not want to touch. 51 | ; 52 | ; Right now these are hacks to leave some specific RAM in place. e.g. 53 | ; the P2/P3 shadow vars and some other things that are important to 54 | ; not clobber 55 | .area _HOME (ABS) 56 | .org 0xC000 57 | .blkb 0x10 ; Unknown? 58 | .blkb 0x1400 ; LCD Buffer 59 | 60 | .org 0xDB90 61 | .blkb 0x40 62 | 63 | .area _CODE 64 | .area _INITIALIZER 65 | .area _GSINIT 66 | .area _GSFINAL 67 | 68 | .area _DATA 69 | .area _INITIALIZED 70 | .area _BSEG 71 | 72 | .area _BSS 73 | 74 | .area _HEAP 75 | 76 | .area _CODE 77 | 78 | ; Unsure what clock does, but leave it in place in case it is called 79 | __clock:: 80 | ret 81 | 82 | ; Upon exit of the app, just reboot the whole Mailstation 83 | _exit:: 84 | jp 0x0000 85 | 86 | ; XXX: For some reason, sdcc 3.8.0 wants to put _GSINIT in data-loc. 87 | ; I've tried re-arranging sections, setting (CON) to all GSINIT 88 | ; areas, etc. For now, just letting this fall in to _CODE does 89 | ; what we want it to. 90 | ; .area _GSINIT 91 | gsinit:: 92 | ld bc, #l__INITIALIZER 93 | ld a, b 94 | or a, c 95 | jr Z, gsinit_next 96 | ld de, #s__INITIALIZED 97 | ld hl, #s__INITIALIZER 98 | ldir 99 | gsinit_next: 100 | 101 | ; .area _GSFINAL 102 | ret 103 | 104 | -------------------------------------------------------------------------------- /src/include/msfont_3x5.h: -------------------------------------------------------------------------------- 1 | #ifndef __MSFONT_3X5_H__ 2 | #define __MSFONT_3X5_H__ 3 | const uint8_t msfont_3x5_bin[] = { 4 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x02, 0x05, 0x05, 5 | 0x00, 0x00, 0x00, 0x05, 0x07, 0x05, 0x07, 0x05, 0x02, 0x07, 0x03, 0x06, 6 | 0x07, 0x05, 0x04, 0x02, 0x01, 0x05, 0x06, 0x01, 0x06, 0x05, 0x06, 0x02, 7 | 0x02, 0x00, 0x00, 0x00, 0x04, 0x02, 0x02, 0x02, 0x04, 0x01, 0x02, 0x02, 8 | 0x02, 0x01, 0x05, 0x02, 0x05, 0x00, 0x00, 0x00, 0x02, 0x07, 0x02, 0x00, 9 | 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 10 | 0x00, 0x00, 0x02, 0x04, 0x04, 0x02, 0x01, 0x01, 0x07, 0x05, 0x05, 0x05, 11 | 0x07, 0x02, 0x03, 0x02, 0x02, 0x02, 0x03, 0x04, 0x02, 0x01, 0x07, 0x03, 12 | 0x04, 0x02, 0x04, 0x03, 0x05, 0x05, 0x07, 0x04, 0x04, 0x07, 0x01, 0x03, 13 | 0x04, 0x03, 0x02, 0x01, 0x03, 0x05, 0x02, 0x07, 0x04, 0x02, 0x02, 0x02, 14 | 0x02, 0x05, 0x02, 0x05, 0x02, 0x02, 0x05, 0x06, 0x04, 0x02, 0x00, 0x02, 15 | 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x02, 0x01, 0x04, 0x02, 0x01, 0x02, 16 | 0x04, 0x00, 0x07, 0x00, 0x07, 0x00, 0x01, 0x02, 0x04, 0x02, 0x01, 0x03, 17 | 0x04, 0x02, 0x00, 0x02, 0x02, 0x05, 0x05, 0x01, 0x02, 0x02, 0x05, 0x07, 18 | 0x05, 0x05, 0x03, 0x05, 0x03, 0x05, 0x03, 0x06, 0x01, 0x01, 0x01, 0x06, 19 | 0x03, 0x05, 0x05, 0x05, 0x03, 0x07, 0x01, 0x03, 0x01, 0x07, 0x07, 0x01, 20 | 0x03, 0x01, 0x01, 0x06, 0x01, 0x01, 0x05, 0x06, 0x05, 0x05, 0x07, 0x05, 21 | 0x05, 0x07, 0x02, 0x02, 0x02, 0x07, 0x04, 0x04, 0x04, 0x05, 0x02, 0x05, 22 | 0x05, 0x03, 0x05, 0x05, 0x01, 0x01, 0x01, 0x01, 0x07, 0x05, 0x07, 0x05, 23 | 0x05, 0x05, 0x03, 0x05, 0x05, 0x05, 0x05, 0x02, 0x05, 0x05, 0x05, 0x02, 24 | 0x03, 0x05, 0x03, 0x01, 0x01, 0x02, 0x05, 0x05, 0x03, 0x06, 0x03, 0x05, 25 | 0x03, 0x05, 0x05, 0x06, 0x01, 0x02, 0x04, 0x03, 0x07, 0x02, 0x02, 0x02, 26 | 0x02, 0x05, 0x05, 0x05, 0x05, 0x06, 0x05, 0x05, 0x05, 0x05, 0x02, 0x05, 27 | 0x05, 0x05, 0x07, 0x05, 0x05, 0x05, 0x02, 0x05, 0x05, 0x05, 0x05, 0x02, 28 | 0x02, 0x02, 0x07, 0x04, 0x02, 0x01, 0x07, 0x06, 0x02, 0x02, 0x02, 0x06, 29 | 0x01, 0x01, 0x02, 0x04, 0x04, 0x03, 0x02, 0x02, 0x02, 0x03, 0x02, 0x05, 30 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x01, 0x02, 0x00, 0x00, 31 | 0x00, 0x00, 0x06, 0x05, 0x05, 0x06, 0x01, 0x03, 0x05, 0x05, 0x03, 0x00, 32 | 0x06, 0x01, 0x01, 0x06, 0x04, 0x06, 0x05, 0x05, 0x06, 0x00, 0x06, 0x05, 33 | 0x03, 0x06, 0x04, 0x02, 0x07, 0x02, 0x02, 0x00, 0x06, 0x05, 0x06, 0x03, 34 | 0x01, 0x01, 0x03, 0x05, 0x05, 0x02, 0x00, 0x02, 0x02, 0x02, 0x04, 0x00, 35 | 0x04, 0x05, 0x02, 0x01, 0x05, 0x03, 0x05, 0x05, 0x03, 0x02, 0x02, 0x02, 36 | 0x07, 0x00, 0x07, 0x07, 0x05, 0x05, 0x00, 0x03, 0x05, 0x05, 0x05, 0x00, 37 | 0x02, 0x05, 0x05, 0x02, 0x00, 0x03, 0x05, 0x03, 0x01, 0x00, 0x06, 0x05, 38 | 0x06, 0x04, 0x00, 0x05, 0x03, 0x01, 0x01, 0x00, 0x06, 0x03, 0x04, 0x03, 39 | 0x02, 0x07, 0x02, 0x02, 0x04, 0x00, 0x05, 0x05, 0x05, 0x06, 0x00, 0x05, 40 | 0x05, 0x05, 0x02, 0x00, 0x05, 0x05, 0x07, 0x07, 0x00, 0x05, 0x02, 0x02, 41 | 0x05, 0x00, 0x05, 0x05, 0x06, 0x03, 0x00, 0x07, 0x06, 0x03, 0x07, 0x06, 42 | 0x02, 0x03, 0x02, 0x06, 0x02, 0x02, 0x00, 0x02, 0x02, 0x03, 0x02, 0x06, 43 | 0x02, 0x03, 0x00, 0x06, 0x03, 0x00, 0x00 44 | }; 45 | const uint16_t msfont_3x5_bin_len = 475; 46 | #endif //__MSFONT_3X5_H__ 47 | -------------------------------------------------------------------------------- /src/tools/msloader/README.md: -------------------------------------------------------------------------------- 1 | # Loading data on the Mailstation 2 | There are two parts to sending and receiving data, the Mailstation side and a host PC side. This folder contains the Mailstation side while the host PC side can be found in `src/host/mailtransfer/`. 3 | 4 | The `mailtransfer` tools is used to send data (including larger applications) from a host PC to the Mailstation through the parallel port. A `Laplink` compatible cable is required for this operation. See the [wiki documentation](https://github.com/kbembedded/mailstation/wiki/Loading-Data-on-to-the-Mailstation) for more detailed information. 5 | 6 | ## Loader 7 | The mailstation side uses `MS Loader` as provided by the `msloader` binary. This is intended to supersede the original `Loader` application made by the community a long time ago. 8 | 9 | The loader is set up in three stages, stage 0, is the `LDR` app which is similar to the original `Loader` but has been reduced in size to ease manual entry. Stage 1, `msloader-LDR` is an intermediate loader, its sole purpose is to relocate the stage 2 loader to a different address and jump to it. Since stage 0 always loads and runs to 0x8000 and stage 2 is meant to run from 0x4000, stage 1 has stage 2 appended to it and is designed to relocate stage 2 elsewhere in RAM, map that page to slot4, and then jump to it. Stage 2 is the actual `MS Loader`, is interactive and is currently able to load and run other binaries from the parallel port that built with an org of 0x4000 or 0x8000. It is itself built with an org of 0x4000 so it can be written as-is to dataflash and run as a normal application. See the aforementioned wiki documentation for detailed installation instructions. 10 | 11 | Communication between a PC and the Mailstation is a full-duplex link with handshaking. This results in 3-bit wide data between the two devices, dubbed "tribbles" of data. 12 | 13 | The `MS Loader` application can perform a number of tasks. It can load to RAM and execute a binary with an org of 0x4000 or 0x8000. Reboot the Mailstation (this currently works but has an odd side effect of the Mailstation thinking it crashed and running a checkdisk basically). Power off the mailstation. Enter a free-type mode to demo text input. And finally it can dump either the Codeflash or Dataflash in its entirety to a host PC. See the `src/host/mailtransfer` utility for more information on sending data from the Mailstation to a PC. 14 | 15 | ### Build 16 | Run `make` from this directory. 17 | 18 | `LDR.bin` is the stage 0 binary that when written to dataflash will make an application named `LDR`. See the wiki for information on this. Building this will also output the necessary bytes to write to the terminal for ease of use. 19 | 20 | `msloader-LDR.bin` is the stage 1 binary with the stage 2 binary directly appended to it. Load and run this if the Mailstation has only the stage 0 loader, `LDR`; or if the Mailstation is using the orignal `Loader` application. 21 | 22 | `msloader.bin` is the stage 2 binary. Uploading and running this from 0x4000 will give the option to self-update the current stage 2 loader in dataflash. Generally, you won't use this binary directly unless you want to update the stage 2 `MS Loader` already in dataflash. 23 | 24 | Note that at this time, this loader is hard-coded to self-write to the dataflash App 0 location. This will be expanded in the future. 25 | 26 | -------------------------------------------------------------------------------- /src/mslib/graphics-textmode.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | /* Copyright (c) 2020 KBEmbedded */ 3 | 4 | #include 5 | #include 6 | 7 | #include "lcd.h" 8 | #include "ms_ports.h" 9 | 10 | #include "msfont_3x5.h" 11 | 12 | static uint8_t x_pos, y_pos; 13 | static uint8_t y_min, y_max, x_min, x_max; 14 | static uint8_t invert; 15 | 16 | void g_textmode_set_invert(uint8_t inv) { invert = inv ? 0xFF : 0x00; } 17 | void g_textmode_set_ypos(uint8_t new_pos) { y_pos = new_pos; } 18 | void g_textmode_set_xpos(uint8_t new_pos) { x_pos = new_pos; } 19 | uint8_t g_textmode_get_ypos(void) { return y_pos; } 20 | uint8_t g_textmode_get_xpos(void) { return x_pos; } 21 | 22 | void g_textmode_clear_line(uint8_t line) 23 | { 24 | uint8_t cnt; 25 | uint8_t *buf = (uint8_t *)0xc010; 26 | 27 | buf += (line * 6); 28 | 29 | for (cnt = 0; cnt < 40; cnt++) { 30 | memset(buf, invert, 6); 31 | buf += 0x80; 32 | } 33 | } 34 | 35 | void g_textmode_invert_line(uint8_t line) 36 | { 37 | uint8_t cnt, i; 38 | uint8_t *buf = (uint8_t *)0xc010; 39 | 40 | buf += (line * 6); 41 | 42 | for (cnt = 0; cnt < 40; cnt++) { 43 | for (i = 0; i < 6; i++) { 44 | *buf = *buf ^ 0xFF; 45 | buf++; 46 | } 47 | buf += 0x80 - 6; 48 | } 49 | } 50 | 51 | static void g_textmode_scroll(void) 52 | { 53 | uint8_t cnt; 54 | uint8_t *buf = (uint8_t *)0xc010; 55 | 56 | /* The magic number of 0x7A is 0x80 - 6 is the height of a column 57 | * minus the height of a single char. */ 58 | for (cnt = 0; cnt < 40; cnt++) { 59 | memcpy(buf, buf + 6, 0x80 - 6); 60 | buf += 0x80 - 6; 61 | memset(buf, invert, 6); 62 | buf += 6; 63 | } 64 | 65 | } 66 | 67 | int putchar(int val) 68 | { 69 | uint8_t i; 70 | uint8_t *buf = (uint8_t *)0xc010; 71 | uint8_t line_buf; 72 | int translated_val; 73 | 74 | if (val == 0x00) return 0; 75 | 76 | if (val == '\n') { 77 | y_pos++; 78 | x_pos = 0; 79 | } else { 80 | buf += (((x_pos >> 1) * 0x80) + (y_pos * 6)); 81 | translated_val = (val - 32) * 5; 82 | 83 | /* Odd characters in this font are the upper 4 bits. 84 | * In each byte0wide line, it is the right character. */ 85 | if ((x_pos & 1)) { 86 | for (i = 0; i < 5; i++) { 87 | line_buf = *buf; 88 | /* Clear upper 4 bits, leave lower */ 89 | line_buf &= ~0xF0; 90 | line_buf |= (((invert ^ msfont_3x5_bin[(translated_val++)]) << 4) & 0xF0); 91 | *(buf++) = line_buf; 92 | } 93 | /* Even characters with this font are the lower 4 bits. 94 | * For a given byte-wide line, the left character is the 95 | * low nibble. */ 96 | } else { 97 | for (i = 0; i < 5; i++) { 98 | line_buf = *buf; 99 | /* Clear lower 4 bits, leave upper */ 100 | line_buf &= ~0x0F; 101 | line_buf |= ((invert ^ msfont_3x5_bin[(translated_val++)]) & 0x0F); 102 | *(buf++) = line_buf; 103 | } 104 | } 105 | 106 | x_pos++; 107 | if (x_pos > x_max) { 108 | y_pos++; 109 | x_pos = x_min; 110 | } 111 | } 112 | 113 | if (y_pos > y_max) { 114 | g_textmode_scroll(); 115 | y_pos--; 116 | } 117 | 118 | return 0; 119 | } 120 | 121 | void g_textmode_init(void) 122 | { 123 | /* Clear the display and reset our location pointer */ 124 | lcd_buf_clr(); 125 | x_pos = y_pos = 0; 126 | x_min = y_min = 0; 127 | x_max = 79; 128 | y_max = 20; 129 | } 130 | -------------------------------------------------------------------------------- /src/tools/msloader/loadrun.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | /* Copyright (c) 2020 KBEmbedded */ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | /* mslib headers */ 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "loadrun.h" 17 | #include "interface.h" 18 | #include "parport_method.h" 19 | 20 | const struct opt_tbl loadrun_opts[] = { 21 | { " Load to RAM and execute from 0x4000 (limited to single 16kbyte page)\n", loadrun_from_4000 }, 22 | { " Load to RAM and execute from 0x8000 (limited to single 16kbyte page)\n", loadrun_from_8000 }, 23 | { NULL, NULL }, 24 | }; 25 | 26 | void loadrun_from_parport(void) 27 | { 28 | cur_opts = loadrun_opts; 29 | draw_header(); 30 | draw_options(); 31 | } 32 | 33 | uint16_t load_from_parport(volatile uint8_t *buf) 34 | { 35 | uint16_t ret; 36 | uint8_t i; 37 | uint8_t timeout; 38 | uint16_t len = 0, len_q; 39 | 40 | /* Its possible we're running from RAM, but unlikely. Regardless, this 41 | * would mean we're in page 2 of RAM due to the stage 1 loading 42 | * process. Lets load up page 1 as this should be free. 43 | */ 44 | 45 | SLOT8_DEV = DEV_RAM; 46 | SLOT8_PAGE = 0x1; 47 | 48 | for (i = 0; i < 2; i++) { 49 | timeout = 0; 50 | while(1) { 51 | ret = (*parport_read_ptr)(); 52 | if (ret & 0xFF00) { 53 | len = len >> 8; 54 | len |= ((ret & 0xFF) << 8); 55 | break; 56 | } else { 57 | timeout++; 58 | if (timeout == 11) return 0; 59 | } 60 | } 61 | } 62 | 63 | if (len > 0x4000) { 64 | printf("Binary being sent is greater than 16 KiB, aborting!\n"); 65 | lcd_update(); 66 | msfw_delay(5000); 67 | __asm__ ("jp 0x4000"); 68 | } 69 | 70 | /* This printf, since not a static string, includes a lot 71 | * of overhead in the sdcc library to support it */ 72 | printf("Expecting binary that is %05d bytes long\n", len); 73 | lcd_update(); 74 | len_q = len; 75 | for (; len; len--) { 76 | timeout = 0; 77 | while(1) { 78 | ret = (*parport_read_ptr)(); 79 | if (ret & 0xFF00) { 80 | *(buf++) = (ret & 0xFF); 81 | break; 82 | } else { 83 | timeout++; 84 | if (timeout == 11) return 0; 85 | } 86 | } 87 | } 88 | 89 | return len_q; 90 | } 91 | 92 | void loadrun_from_8000(void) 93 | { 94 | g_textmode_init(); 95 | printf("Loading binary to 0x8000 and executing\n"); 96 | lcd_update(); 97 | 98 | if (!load_from_parport((volatile uint8_t *)0x8000)) { 99 | printf("Error! Loading timed out / no data received!\n"); 100 | lcd_update(); 101 | msfw_delay(5000); 102 | __asm__ ("jp 0x4000"); 103 | } 104 | 105 | __asm__ ("jp 0x8000"); 106 | } 107 | 108 | void load_4000_trampoline(void) __naked 109 | { 110 | SLOT4_DEV = DEV_RAM; 111 | SLOT4_PAGE = 0x1; 112 | __asm__ ("jp 0x4000"); 113 | } 114 | 115 | void loadrun_from_4000(void) 116 | { 117 | g_textmode_init(); 118 | printf("Loading binary to 0x4000 and executing\n"); 119 | lcd_update(); 120 | 121 | if (!load_from_parport((volatile uint8_t *)0x8000)) { 122 | printf("Error! Loading timed out / no data received!\n"); 123 | lcd_update(); 124 | msfw_delay(5000); 125 | __asm__ ("jp 0x4000"); 126 | } 127 | 128 | /* Clobber all of our graphics buffer, overkill, but its a known 129 | * value that needs to be kept to. It beats trying to calculate the 130 | * exact length of our trampoline. 131 | */ 132 | memcpy((uint8_t *)0xC010, load_4000_trampoline, 0x1400); 133 | __asm__ ("jp 0xC010"); 134 | } 135 | -------------------------------------------------------------------------------- /src/demos/FyOS/v0.01/getchar.s: -------------------------------------------------------------------------------- 1 | 2 | .area _BSS 3 | 4 | mycharbuffer: ; Scancode buffer for _getchar 5 | .ds 2 6 | 7 | 8 | getkeycodefrombuffer = #0x0A9A ; Mailstation function 9 | 10 | 11 | ;------------------------------------------------------------------------------ 12 | ; scancode_table holds two tables of ascii characters which '_getchar' uses 13 | ; to determine which character to return, depending on the scancode pressed 14 | ; and the state of the shift key. 15 | ;------------------------------------------------------------------------------ 16 | 17 | .area _DATA 18 | scancode_table: 19 | .include 'scancode_table.inc' 20 | 21 | 22 | ;------------------------------------------------------------------------------ 23 | ;------------------------------------------------------------------------------ 24 | 25 | .area _CODE 26 | 27 | 28 | multiply: 29 | ; multiply h by e and return 16 bit result in hl. The b and d 30 | ; register will be zeroed on exit. Requires between 301 and 349 31 | ; clock cycles. 32 | ; 33 | ; Needed by '_getchar', below. 34 | ; 35 | push bc 36 | push de 37 | push af 38 | ld d, #0 39 | ld l, d 40 | ld b, #8 41 | multiply_NEXT: 42 | add hl, hl 43 | jr nc, multiply_NOADD 44 | add hl, de 45 | multiply_NOADD: 46 | djnz multiply_NEXT 47 | pop af 48 | pop de 49 | pop bc 50 | ret 51 | 52 | 53 | ;------------------------------------------------------------------------------ 54 | ; _getchar 55 | ; 56 | ; Parameters: none 57 | ; Returns: ASCII character code in 'l' register 58 | ; 59 | ; Waits for a scancode using the Mailstation firmware's getkeycodefrombuffer 60 | ; function (0x0A9A), then uses the two conversion tables at 'scancode_table' 61 | ; to determine the ascii character depending on the state of the shift key. 62 | ; Currently does not handle extended keys or caps lock. 63 | ; 64 | ;------------------------------------------------------------------------------ 65 | _getchar:: 66 | keyagain: 67 | ; wait till a key is available 68 | ld de, #mycharbuffer 69 | push de 70 | call getkeycodefrombuffer 71 | pop de 72 | jp z, keyagain 73 | 74 | ld a, (mycharbuffer+1) ; Got a scancode; check its state 75 | bit 0, a 76 | jp z, keyagain ; if key released, we don't care, get another 77 | ld a, (mycharbuffer) 78 | and #0x0F ; save low nibble in b 79 | ld b, a 80 | ld a, (mycharbuffer) 81 | srl a ; save high nibble in c 82 | srl a 83 | srl a 84 | srl a 85 | ld c, a 86 | ld h, #8 ; hl = 8 * high nibble 87 | ld e, c 88 | call multiply 89 | ld a, b ; low nibble + (8 * high nibble) 90 | add l 91 | ld b, #0 ; bc = position in scancode_table 92 | ld c, a 93 | ld hl, #scancode_table ; hl = scancode_table + offset (starting in lowercase codes) 94 | add hl, bc 95 | ld a, (mycharbuffer+1) ; check if shift/capslock 96 | bit 6, a 97 | jr nz, do_ascii_caps 98 | ;bit 5, a ; actually don't check capslock for now, that only affects letters 99 | ;jr nz, get_ascii_caps 100 | jr get_ascii_char ; no caps, so just get lowercase 101 | do_ascii_caps: 102 | ld bc, #0d80 103 | add hl, bc 104 | get_ascii_char: 105 | ld a, (hl) 106 | or a ; check if ascii = 0 107 | jr z, print_scan_char 108 | cp a, #0d255 ; check if ascii = 255 109 | jr z, print_scan_char 110 | ld a, (hl) ; print ascii code 111 | jr print_ascii_char 112 | print_scan_char: 113 | jp keyagain ; Let's not deal with extended keys for now 114 | ;jr checkbutton 115 | ;ld a, #0 116 | ;ld a, (mycharbuffer) ; otherwise load original scan code 117 | ;ld l, a 118 | ;ret 119 | print_ascii_char: 120 | ld l, a ; Return ascii code 121 | ret 122 | 123 | 124 | -------------------------------------------------------------------------------- /src/demos/FyOS/v0.02/getchar.s: -------------------------------------------------------------------------------- 1 | 2 | .area _BSS 3 | 4 | mycharbuffer: ; Scancode buffer for _getchar 5 | .ds 2 6 | 7 | 8 | getkeycodefrombuffer = #0x0A9A ; Mailstation function 9 | 10 | 11 | ;------------------------------------------------------------------------------ 12 | ; scancode_table holds two tables of ascii characters which '_getchar' uses 13 | ; to determine which character to return, depending on the scancode pressed 14 | ; and the state of the shift key. 15 | ;------------------------------------------------------------------------------ 16 | 17 | .area _DATA 18 | scancode_table: 19 | .include 'scancode_table.inc' 20 | 21 | 22 | ;------------------------------------------------------------------------------ 23 | ;------------------------------------------------------------------------------ 24 | 25 | .area _CODE 26 | 27 | 28 | multiply: 29 | ; multiply h by e and return 16 bit result in hl. The b and d 30 | ; register will be zeroed on exit. Requires between 301 and 349 31 | ; clock cycles. 32 | ; 33 | ; Needed by '_getchar', below. 34 | ; 35 | push bc 36 | push de 37 | push af 38 | ld d, #0 39 | ld l, d 40 | ld b, #8 41 | multiply_NEXT: 42 | add hl, hl 43 | jr nc, multiply_NOADD 44 | add hl, de 45 | multiply_NOADD: 46 | djnz multiply_NEXT 47 | pop af 48 | pop de 49 | pop bc 50 | ret 51 | 52 | 53 | ;------------------------------------------------------------------------------ 54 | ; _getchar 55 | ; 56 | ; Parameters: none 57 | ; Returns: ASCII character code in 'l' register 58 | ; 59 | ; Waits for a scancode using the Mailstation firmware's getkeycodefrombuffer 60 | ; function (0x0A9A), then uses the two conversion tables at 'scancode_table' 61 | ; to determine the ascii character depending on the state of the shift key. 62 | ; Currently does not handle extended keys or caps lock. 63 | ; 64 | ;------------------------------------------------------------------------------ 65 | _getchar:: 66 | keyagain: 67 | ; wait till a key is available 68 | ld de, #mycharbuffer 69 | push de 70 | call getkeycodefrombuffer 71 | pop de 72 | jp z, keyagain 73 | 74 | ld a, (mycharbuffer+1) ; Got a scancode; check its state 75 | bit 0, a 76 | jp z, keyagain ; if key released, we don't care, get another 77 | ld a, (mycharbuffer) 78 | and #0x0F ; save low nibble in b 79 | ld b, a 80 | ld a, (mycharbuffer) 81 | srl a ; save high nibble in c 82 | srl a 83 | srl a 84 | srl a 85 | ld c, a 86 | ld h, #8 ; hl = 8 * high nibble 87 | ld e, c 88 | call multiply 89 | ld a, b ; low nibble + (8 * high nibble) 90 | add l 91 | ld b, #0 ; bc = position in scancode_table 92 | ld c, a 93 | ld hl, #scancode_table ; hl = scancode_table + offset (starting in lowercase codes) 94 | add hl, bc 95 | ld a, (mycharbuffer+1) ; check if shift/capslock 96 | bit 6, a 97 | jr nz, do_ascii_caps 98 | ;bit 5, a ; actually don't check capslock for now, that only affects letters 99 | ;jr nz, get_ascii_caps 100 | jr get_ascii_char ; no caps, so just get lowercase 101 | do_ascii_caps: 102 | ld bc, #0d80 103 | add hl, bc 104 | get_ascii_char: 105 | ld a, (hl) 106 | or a ; check if ascii = 0 107 | jr z, print_scan_char 108 | cp a, #0d255 ; check if ascii = 255 109 | jr z, print_scan_char 110 | ld a, (hl) ; print ascii code 111 | jr print_ascii_char 112 | print_scan_char: 113 | jp keyagain ; Let's not deal with extended keys for now 114 | ;jr checkbutton 115 | ;ld a, #0 116 | ;ld a, (mycharbuffer) ; otherwise load original scan code 117 | ;ld l, a 118 | ;ret 119 | print_ascii_char: 120 | ld l, a ; Return ascii code 121 | ret 122 | 123 | 124 | -------------------------------------------------------------------------------- /src/mslib/dflash_write.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | /* Copyright (c) 2020 KBEmbedded */ 3 | 4 | #include 5 | 6 | #include "ms_ports.h" 7 | 8 | static void dflash_sdp_seq(void) 9 | { 10 | *(volatile uint8_t *)0x9823; 11 | *(volatile uint8_t *)0x9820; 12 | *(volatile uint8_t *)0x9822; 13 | *(volatile uint8_t *)0x8418; 14 | *(volatile uint8_t *)0x841B; 15 | *(volatile uint8_t *)0x8419; 16 | } 17 | 18 | /* Read a location twice and compare until both values match. This indicates 19 | * a write success */ 20 | static void dflash_wait_write(void) 21 | { 22 | volatile uint8_t *dat = (volatile uint8_t *)0x8000; 23 | 24 | while ((*dat != *dat)); 25 | } 26 | 27 | /* Can be run from any page */ 28 | void dflash_unlock(void) 29 | { 30 | dflash_sdp_seq(); 31 | *(volatile uint8_t *)0x841A; 32 | } 33 | 34 | void dflash_lock(void) 35 | { 36 | dflash_sdp_seq(); 37 | *(volatile uint8_t *)0x840A; 38 | } 39 | 40 | /* Command sequence according to datasheet is: 41 | * Write 0x20 to any address 42 | * Read from sector aligned address to erase 43 | * Write 0xD0 to any address 44 | * Wait for write completion marker 45 | * Verify whole sector returns 0xFF 46 | */ 47 | uint8_t dflash_erase_sector(uint16_t adr) 48 | { 49 | volatile uint8_t *buf; 50 | uint8_t i = 0; 51 | /* Addresses passed here _should_ be 256 byte aligned, but force them 52 | * to be anyway. Not sure what the flash does when address is not 53 | * aligned to sector/256byte. */ 54 | adr = adr & 0xFF00; 55 | 56 | /* Ensure that address range is within 0x8000 - 0xBFFF, slot8. This 57 | * is not something we can recover from here. */ 58 | if (adr < 0x8000 || adr > 0xBFFF) return 1; 59 | 60 | buf = (uint8_t *)adr; 61 | 62 | /* Handle erase sequence and verify */ 63 | *buf = 0x20; 64 | *buf; 65 | *buf = 0xD0; 66 | dflash_wait_write(); 67 | 68 | do { 69 | if (*(buf++) != 0xFF) return 1; 70 | i++; 71 | } while(i); 72 | 73 | return 0; 74 | } 75 | 76 | /* Command sequence according to datasheet is: 77 | * Write 0x10 to any address 78 | * Write data to specified address 79 | * Wait for write completion marker 80 | * Verify written data matches requested data 81 | */ 82 | uint8_t dflash_write_byte(uint16_t adr, uint8_t dat) 83 | { 84 | /* Ensure that address range is within 0x8000 - 0xBFFF, slot8. This 85 | * is not something we can recover from here. */ 86 | if (adr < 0x8000 || adr > 0xBFFF) return 1; 87 | 88 | /* Set up write and then write data */ 89 | *(volatile uint8_t *)adr = 0x10; 90 | *(volatile uint8_t *)adr = dat; 91 | dflash_wait_write(); 92 | 93 | /* Its slightly smaller code with SDCC to use this if block than to 94 | * return the inverted comparison */ 95 | if (dat == *(volatile uint8_t *)adr) return 0; 96 | else return 1; 97 | } 98 | 99 | /* Follows the same process as in write_byte, but does a full sector, slightly 100 | * more efficient */ 101 | uint8_t dflash_write_sector(uint16_t adr, uint8_t *dat) 102 | { 103 | uint8_t i = 0; 104 | 105 | /* Addresses passed here _should_ be 256 byte aligned, fail if this 106 | * is not the case as we cannot safely correct this. */ 107 | if (adr & 0xFF) return 1; 108 | 109 | /* Ensure that address range is within 0x8000 - 0xBFFF, slot8. This 110 | * is not something we can recover from here. */ 111 | if (adr < 0x8000 || adr > 0xBFFF) return 1; 112 | 113 | do { 114 | /* Set up write and then write data */ 115 | *(volatile uint8_t *)adr = 0x10; 116 | *(volatile uint8_t *)(adr++) = *(dat++); 117 | dflash_wait_write(); 118 | i++; 119 | } while (i); 120 | 121 | /* Verify written data */ 122 | dat = dat - 256; 123 | adr = adr - 256; 124 | do { 125 | if (*(dat++) != *(volatile uint8_t *)(adr++)) return 1; 126 | } while (i); 127 | 128 | return 0; 129 | } 130 | 131 | # if 0 132 | void dflash_erase_chip(void) 133 | { 134 | volatile uint8_t *dat = (volatile uint8_t *)0x8000; 135 | 136 | *dat = 0x30; 137 | *dat = 0x30; 138 | dflash_wait_write(); 139 | 140 | /* Add verification */ 141 | } 142 | #endif 143 | -------------------------------------------------------------------------------- /src/demos/FyOS/v0.01/crt0.s: -------------------------------------------------------------------------------- 1 | ;; FyOS crt0.s for Z80 2 | .module crt0 3 | .globl _main 4 | 5 | ;------------------------------------------------------------------------------ 6 | ; Initialization code 7 | ;------------------------------------------------------------------------------ 8 | 9 | .area _HEADER (ABS) 10 | .org 0x8000 11 | 12 | ;; Stack at the top of memory. 13 | ;ld sp,#0xffff ; let's not change this for now 14 | 15 | ; preserve old slot4000 for later 16 | ld a, (#06) 17 | ld (startup_slot4000device), a 18 | ld a, (#05) 19 | ld (startup_slot4000page), a 20 | 21 | ; check version for setting shadow vars 22 | ld a, #0 23 | ld (_firmwareversionsafe), a ; safe for now 24 | ld a, (#0x0037) 25 | cp a, #02 ; check major version for v2 26 | jr z, version2checkminor 27 | cp a, #03 ; check major version for v3 28 | jr z, version3checkminor 29 | jr use_defaultversion2 ; if neither major v2 or v3, who knows! use v2.53 30 | version2checkminor: 31 | ld a, (#0x0036) 32 | cp a, #0d53 ; check for v2.53 33 | jr z, use_version253 34 | cp a, #0d54 ; check for v2.54 35 | jr z, use_version254 36 | nop ; else use v2.53 anyway for now 37 | use_defaultversion2: 38 | ld a, #02 39 | ld (_firmwareversionsafe), a ; not safe firmware in use 40 | use_version253: 41 | ld hl, #0xdba1 ; set shadow vars 42 | ld (_p2shadow), hl 43 | ld hl, #0xdba2 44 | ld (_p3shadow), hl 45 | jr versioncheckcomplete 46 | use_version254: 47 | ld hl, #0xdba2 ; set shadow vars 48 | ld (_p2shadow), hl 49 | ld hl, #0xdba3 50 | ld (_p3shadow), hl 51 | jr versioncheckcomplete 52 | 53 | version3checkminor: 54 | ld a, (#0x0036) 55 | cp a, #0d3 ; check for v3.03 56 | jr z, use_version303 57 | nop ; else use v3.03 anyway for now 58 | use_defaultversion3: 59 | ld a, #0d3 60 | ld (_firmwareversionsafe), a ; not safe firmware in use 61 | use_version303: 62 | ld hl, #0xdba5 ; set shadow vars 63 | ld (_p2shadow), hl 64 | ld hl, #0xdba6 65 | ld (_p3shadow), hl 66 | jr versioncheckcomplete 67 | 68 | versioncheckcomplete: 69 | 70 | 71 | call gsinit ; Initialize global variables 72 | call _main ; Run main C code 73 | jp _exit ; Do exit procedure 74 | 75 | 76 | ;------------------------------------------------------------------------------ 77 | ; Ordering of segments for the linker. 78 | ;------------------------------------------------------------------------------ 79 | 80 | .area _HOME 81 | .area _CODE 82 | .area _GSINIT 83 | .area _GSFINAL 84 | .area _DATA 85 | .area _BSS 86 | .area _HEAP 87 | 88 | 89 | ;------------------------------------------------------------------------------ 90 | ; Some basic code segments: __clock and _exit. 91 | ; 92 | ; No idea what __clock is, so we just return. 93 | ; 94 | ; _exit is run when your 'main' C function returns. 95 | ;------------------------------------------------------------------------------ 96 | 97 | .area _CODE 98 | 99 | ;------------------------------------------------------------------------------ 100 | 101 | __clock:: 102 | ;ld a,#2 103 | ;rst 0x08 104 | ret 105 | 106 | ;------------------------------------------------------------------------------ 107 | 108 | _exit:: 109 | 110 | ; restore slot4000, jump to app 111 | ld a, (startup_slot4000device) 112 | ld (#06),a 113 | ld a, (startup_slot4000page) 114 | ld (#05),a 115 | jp 0x4000 116 | 117 | 118 | ;------------------------------------------------------------------------------ 119 | ; This area is where code gets inserted automatically to inialize variables. 120 | ;------------------------------------------------------------------------------ 121 | 122 | .area _GSINIT 123 | gsinit:: 124 | ld bc, #l__INITIALIZER 125 | ld a, b 126 | or a, c 127 | jr Z, gsinit_next 128 | ld de, #s__INITIALIZED 129 | ld hl, #s__INITIALIZER 130 | ldir 131 | gsinit_next: 132 | .area _GSFINAL 133 | ret 134 | 135 | 136 | ;------------------------------------------------------------------------------ 137 | ; Some variables we'll need. 138 | ;------------------------------------------------------------------------------ 139 | 140 | .area _BSS 141 | 142 | startup_slot4000device: 143 | .ds 1 144 | startup_slot4000page: 145 | .ds 1 146 | _p2shadow:: 147 | .ds 2 148 | _p3shadow:: 149 | .ds 2 150 | _firmwareversionsafe:: 151 | .ds 1 152 | 153 | -------------------------------------------------------------------------------- /src/demos/FyOS/v0.02/crt0.s: -------------------------------------------------------------------------------- 1 | ;; FyOS crt0.s for Z80 2 | .module crt0 3 | .globl _main 4 | 5 | ;------------------------------------------------------------------------------ 6 | ; Initialization code 7 | ;------------------------------------------------------------------------------ 8 | 9 | .area _HEADER (ABS) 10 | .org 0x8000 11 | 12 | ;; Stack at the top of memory. 13 | ;ld sp,#0xffff ; let's not change this for now 14 | 15 | ; preserve old slot4000 for later 16 | ld a, (#06) 17 | ld (startup_slot4000device), a 18 | ld a, (#05) 19 | ld (startup_slot4000page), a 20 | 21 | ; check version for setting shadow vars 22 | ld a, #0 23 | ld (_firmwareversionsafe), a ; safe for now 24 | ld a, (#0x0037) 25 | cp a, #02 ; check major version for v2 26 | jr z, version2checkminor 27 | cp a, #03 ; check major version for v3 28 | jr z, version3checkminor 29 | jr use_defaultversion2 ; if neither major v2 or v3, who knows! use v2.53 30 | version2checkminor: 31 | ld a, (#0x0036) 32 | cp a, #0d53 ; check for v2.53 33 | jr z, use_version253 34 | cp a, #0d54 ; check for v2.54 35 | jr z, use_version254 36 | nop ; else use v2.53 anyway for now 37 | use_defaultversion2: 38 | ld a, #02 39 | ld (_firmwareversionsafe), a ; not safe firmware in use 40 | use_version253: 41 | ld hl, #0xdba1 ; set shadow vars 42 | ld (_p2shadow), hl 43 | ld hl, #0xdba2 44 | ld (_p3shadow), hl 45 | jr versioncheckcomplete 46 | use_version254: 47 | ld hl, #0xdba2 ; set shadow vars 48 | ld (_p2shadow), hl 49 | ld hl, #0xdba3 50 | ld (_p3shadow), hl 51 | jr versioncheckcomplete 52 | 53 | version3checkminor: 54 | ld a, (#0x0036) 55 | cp a, #0d3 ; check for v3.03 56 | jr z, use_version303 57 | nop ; else use v3.03 anyway for now 58 | use_defaultversion3: 59 | ld a, #0d3 60 | ld (_firmwareversionsafe), a ; not safe firmware in use 61 | use_version303: 62 | ld hl, #0xdba5 ; set shadow vars 63 | ld (_p2shadow), hl 64 | ld hl, #0xdba6 65 | ld (_p3shadow), hl 66 | jr versioncheckcomplete 67 | 68 | versioncheckcomplete: 69 | 70 | 71 | call gsinit ; Initialize global variables 72 | call _main ; Run main C code 73 | jp _exit ; Do exit procedure 74 | 75 | 76 | ;------------------------------------------------------------------------------ 77 | ; Ordering of segments for the linker. 78 | ;------------------------------------------------------------------------------ 79 | 80 | .area _HOME 81 | .area _CODE 82 | .area _GSINIT 83 | .area _GSFINAL 84 | .area _DATA 85 | .area _BSS 86 | .area _HEAP 87 | 88 | 89 | ;------------------------------------------------------------------------------ 90 | ; Some basic code segments: __clock and _exit. 91 | ; 92 | ; No idea what __clock is, so we just return. 93 | ; 94 | ; _exit is run when your 'main' C function returns. 95 | ;------------------------------------------------------------------------------ 96 | 97 | .area _CODE 98 | 99 | ;------------------------------------------------------------------------------ 100 | 101 | __clock:: 102 | ;ld a,#2 103 | ;rst 0x08 104 | ret 105 | 106 | ;------------------------------------------------------------------------------ 107 | 108 | _exit:: 109 | 110 | ; restore slot4000, jump to app 111 | ld a, (startup_slot4000device) 112 | ld (#06),a 113 | ld a, (startup_slot4000page) 114 | ld (#05),a 115 | jp 0x4000 116 | 117 | 118 | ;------------------------------------------------------------------------------ 119 | ; This area is where code gets inserted automatically to inialize variables. 120 | ;------------------------------------------------------------------------------ 121 | 122 | .area _GSINIT 123 | gsinit:: 124 | ld bc, #l__INITIALIZER 125 | ld a, b 126 | or a, c 127 | jr Z, gsinit_next 128 | ld de, #s__INITIALIZED 129 | ld hl, #s__INITIALIZER 130 | ldir 131 | gsinit_next: 132 | .area _GSFINAL 133 | ret 134 | 135 | 136 | ;------------------------------------------------------------------------------ 137 | ; Some variables we'll need. 138 | ;------------------------------------------------------------------------------ 139 | 140 | .area _BSS 141 | 142 | startup_slot4000device: 143 | .ds 1 144 | startup_slot4000page: 145 | .ds 1 146 | _p2shadow:: 147 | .ds 2 148 | _p3shadow:: 149 | .ds 2 150 | _firmwareversionsafe:: 151 | .ds 1 152 | 153 | -------------------------------------------------------------------------------- /src/tools/msloader/msloader.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | /* Copyright (c) 2020 KBEmbedded */ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | /* mslib headers */ 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "msloader-app_info.h" 20 | 21 | #include "interface.h" 22 | #include "parport_method.h" 23 | #include "save.h" 24 | #include "loadrun.h" 25 | #include "dump.h" 26 | 27 | 28 | static struct opt_tbl main_opts[] = { 29 | { " Load binary and execute...\n", loadrun_from_parport }, 30 | { " Load binary and write to Dataflash...\n", loadsave_from_parport }, 31 | { " Dump flash...\n", dump_to_parport }, 32 | { " Send flash...\n", send_to_parport }, 33 | { " Select parallel method...\n", sel_parport }, 34 | { " Manage Dataflash...\n", manage_dflash }, 35 | { " Reboot Mailstation\n", restart }, 36 | { " Power off Mailstation\n", poweroff }, 37 | { " Free-type mode\n", freetype }, 38 | { NULL, NULL }, 39 | }; 40 | 41 | static struct opt_tbl ram_opts[] = { 42 | { " Detected that Loader is currently running from RAM, write self to App 0\n", self_write_to_app0 }, 43 | { " Skip this for now\n", go_to_main }, 44 | { NULL, NULL }, 45 | }; 46 | 47 | static void restart(void) __naked 48 | { 49 | /* It appears that if we convince MSOS that RAM was re-initialized, 50 | * then it will think it was a fresh poweron. The marker for this is 51 | * buried somewhere in 0xDXXX which changes from version to version. 52 | * So, disable interrupts, clobber all of SlotC with 0x00, and then 53 | * jump to 0x0000 54 | */ 55 | 56 | __asm 57 | di 58 | ld de, #0xc001 59 | ld hl, #0xc000 60 | ld bc, #0x3fff 61 | xor a 62 | ld (hl), a 63 | ldir 64 | jp 0x0000 65 | __endasm; 66 | } 67 | 68 | static void poweroff(void) 69 | { 70 | msfw_poweroff(); 71 | } 72 | 73 | static void freetype(void) 74 | { 75 | uint8_t scancode_buf[2]; 76 | uint8_t scancode_buf_q = 0; 77 | uint8_t decode; 78 | 79 | g_textmode_init(); 80 | printf("Free type mode, will just echo back characters.\n"); 81 | printf("Press the \"Back\" key to return to the main menu\n"); 82 | lcd_update(); 83 | 84 | while (1) { 85 | while (!msfw_get_scancode(scancode_buf)); 86 | if ((scancode_buf[1] & 0x1) && (scancode_buf_q != scancode_buf[0])) { 87 | scancode_buf_q = scancode_buf[0]; 88 | decode = (scancode_buf[0] & 0x7) | ((scancode_buf[0] & 0xF0) >> 1); 89 | if (scancode_buf[1] & 0x40) decode += 80; 90 | putchar(scode_lower[decode]); 91 | if (scancode_buf[0] == 0x01) { 92 | __asm__ ("jp 0x4000"); 93 | } 94 | lcd_update(); 95 | } else { 96 | scancode_buf_q = 0; 97 | } 98 | } 99 | } 100 | 101 | void go_to_main(void) 102 | { 103 | cur_opts = main_opts; 104 | draw_header(); 105 | draw_options(); 106 | } 107 | 108 | 109 | 110 | void main(void) { 111 | uint8_t *buf = (uint8_t *)0xc010; 112 | uint8_t scancode_buf[2]; 113 | uint8_t scancode_buf_q = 0; 114 | uint8_t decode; 115 | 116 | 117 | /* Since this is built to run from 0x4000, check slot4. If its RAM 118 | * then we need to write ourselves to dataflash app 0. 119 | * TODO: Implement more intelligent handling of this. 120 | */ 121 | if (SLOT4_DEV == DEV_RAM) { 122 | cur_opts = ram_opts; 123 | } else { 124 | cur_opts = main_opts; 125 | } 126 | 127 | draw_header(); 128 | draw_options(); 129 | 130 | 131 | while(1) { 132 | while (!msfw_get_scancode(scancode_buf)); 133 | if ((scancode_buf[1] & 0x1) && (scancode_buf_q != scancode_buf[0])) { 134 | scancode_buf_q = scancode_buf[0]; 135 | decode = (scancode_buf[0] & 0x7) | ((scancode_buf[0] & 0xF0) >> 1); 136 | if (scancode_buf[1] & 0x40) decode += 80; 137 | //putchar(scode_lower[decode]); 138 | switch (scode_lower[decode]) { 139 | case 'h': // Reset to main menu 140 | __asm__ ("jp 0x4000"); 141 | break; 142 | case 'j': // Down 143 | g_textmode_invert_line(line); 144 | line++; 145 | if (line > line_max) line = 4; 146 | g_textmode_invert_line(line); 147 | break; 148 | case 'k': // Up 149 | g_textmode_invert_line(line); 150 | line--; 151 | if (line < 4) line = line_max; 152 | g_textmode_invert_line(line); 153 | break; 154 | case 'l': // Select 155 | cur_opts[line-4].func(); 156 | break; 157 | default: // Shrug 158 | break; 159 | } 160 | } else { 161 | scancode_buf_q = 0; 162 | } 163 | 164 | 165 | lcd_update(); 166 | __asm__ ("halt"); 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/tools/msloader/LDR.s: -------------------------------------------------------------------------------- 1 | ; vim:syntax=z8a 2 | ; 3 | ; SPDX-License-Identifier: BSD-2-Clause 4 | ; Copyright (c) 2020 KBEmbedded 5 | ; 6 | ; A Mailstation app intended to be run from the dataflash app context 7 | ; This means it needs an app header and expects to be run from 0x4000 8 | 9 | ; This loader app is based around the Mailstation app used in spew.s by 10 | ; Cyrano Jones. 11 | ; 12 | ; This code is designed to be as small as possible as it needs to be 13 | ; manually entered via the built-in hex editor inside the Mailstation 14 | ; diagnostic menu. 15 | ; 16 | ; The code below receives first a 16-bit value of the total number of 17 | ; bytes to follow. The first byte sent is the LSB. After that, this will 18 | ; recieve the specified number of bytes which are written directly to 19 | ; RAM page 1 which is set in to slot8000. Once the number of bytes is 20 | ; transferred, this app will jump to the start of slot8000 21 | ; 22 | ; Originally written by FyberOptic 23 | 24 | .module Loader 25 | .area _CODE 26 | .area _DATA 27 | .globl _start 28 | 29 | ; The following function is called from codeflash page 1, attempts to 30 | ; receive a byte from the parallel port. Upon return, if a = 0, then 31 | ; a timeout or other failure occurred. Otherwise, the received byte is 32 | ; placed in the l register. 33 | brecvbyte = 0x8027 34 | 35 | _start: 36 | jp eventhandler ; Jump to the start of our code. 37 | 38 | .dw (icon) 39 | .dw (caption) 40 | .dw (unknown_value) 41 | 42 | ; XXX Might be able to drop unknown value and just put caption there directly? 43 | 44 | ; Normally, this section would have some values needed for app setup, however 45 | ; since we're trying to save bytes and we don't use this information anyway, 46 | ; we don't really care. 47 | unknown_value: 48 | 49 | caption: 50 | .dw #0x0001 ; Unknown meaning 51 | .dw endcap-caption-6 ; Calculate caption length 52 | .dw #0x0006 ; Offset to first character 53 | .ascii "LDR" ; The caption string 54 | endcap: 55 | 56 | icon: 57 | 58 | ;---------------------------------------------------------- 59 | ; Now for the actual code 60 | ;---------------------------------------------------------- 61 | 62 | getbyte: 63 | push de 64 | 65 | xor a ; Put codeflash page 1 into slot8000. 66 | out (#0x08), a 67 | inc a 68 | out (#0x07), a 69 | 70 | getbyte2: 71 | call brecvbyte ; Try to fetch a byte. 72 | or a ; If we didn't get one, try again. 73 | jr z, getbyte2 74 | 75 | pop de 76 | ret 77 | 78 | ; The first two bytes sent are the total number of bytes the loader should recv 79 | ; before jumping in to execution. The low order byte is sent first, then the 80 | ; high order byte. These are saved in to the BC reg which is used as a counter 81 | ; for LDI operations later. DE is loaded with the destination address, 0x8000 82 | eventhandler: 83 | call getbyte ; Returns byte of data in L 84 | ld c, l 85 | 86 | call getbyte ; Returns byte of data in L 87 | ld b, l 88 | 89 | ld de, #0x8000 90 | 91 | ; This function will repeatedly run until we have received all of the expected 92 | ; bytes from the host. On each loop: 93 | ; A byte is received from the parallel port 94 | ; Said byte is pushed to the stack 95 | ; HL is given the SP value (see inline comments for the magic of this) 96 | ; LDI standard pattern is used to copy byte, inc DE and dec BC. 97 | ; Using LDI is smaller than manaully copying bytes and incrementing locations 98 | ; POP our value off the stack to keep the stack balanced. 99 | ; Check overflow (POP has no effect), loop until LDI overflows BC 100 | nextcodebyte: 101 | call getbyte ; Returns byte of data in L 102 | 103 | push hl ; Save HL to stack 104 | 105 | ; Note to myself for later. It might be slightly more compact to move 106 | ; L in to A, then move A in to (DE), inc DE, dec BC and then check for 107 | ; overflow. Would remove push, pop, xor, sbc, add, ldi, but would then 108 | ; add back ld a with 1, out would stay, ld a, l, ld (DE), a, inc de, 109 | ; dec bc. Might not be a net gain but it could reduce the complexity here? 110 | ; These three opcodes are smaller than clearing HL, loading it with SP, 111 | ; and then later loading A with 0x1 to switch the slot8000 device. 112 | ; PUSH loads high-order byte first. That means after PUSH of HL earlier, 113 | ; SP points to the value of L, which is the byte we read from parallel. 114 | xor a ; Clear A reg and the C flag 115 | sbc hl, hl ; Subtract HL-HL-C flag == 0 116 | add hl, sp ; HL now points to old L on the stack 117 | 118 | ; Set RAM page 1 in slot8000. Page 1 already set in P7, reused from 119 | ; CF page 1 set above; so we just need to set RAM to device slot 120 | inc a 121 | out (#0x08), a 122 | 123 | ldi ; LD (HL) == (SP) to (DE) == dest addr, dec BC 124 | pop hl ; Pop HL reg back off the stack, we don't care 125 | ; about it anymore, can be thrown away 126 | 127 | jp pe, nextcodebyte 128 | 129 | jp 0x8000 ; When done, jump to code! 130 | -------------------------------------------------------------------------------- /src/demos/drawimage/crt0-asm.s: -------------------------------------------------------------------------------- 1 | ; SPDX-License-Identifier: BSD-2-Clause 2 | 3 | ; This crt0 still does a lot of the Mailstation setup steps, but it is 4 | ; meant to link against full assembly projects. This is just a stop-gap 5 | ; solution for the time being, and hopefully this should all get cleaned 6 | ; up later. 7 | ; Specifically, this file drops definitions for l_INITIALIZER, 8 | ; s_INITIALIZED, and s_INITIALIZER. All three of which are emitted from 9 | ; sdcc, but not sdasz80 10 | 11 | ; Originally created by FyberOptic and/or Cyrano Jones 12 | 13 | .module crt0 14 | .globl _main 15 | 16 | ;------------------------------------------------------------------------------ 17 | ; Initialization code 18 | ;------------------------------------------------------------------------------ 19 | 20 | .area _HEADER (ABS) 21 | .org 0x8000 22 | 23 | ;; Stack at the top of memory. 24 | ;ld sp,#0xffff ; let's not change this for now 25 | 26 | ; preserve old slot4000 for later 27 | ld a, (#06) 28 | ld (startup_slot4000device), a 29 | ld a, (#05) 30 | ld (startup_slot4000page), a 31 | 32 | ; check version for setting shadow vars 33 | ld a, #0 34 | ld (_firmwareversionsafe), a ; safe for now 35 | ld a, (#0x0037) 36 | cp a, #02 ; check major version for v2 37 | jr z, version2checkminor 38 | cp a, #03 ; check major version for v3 39 | jr z, version3checkminor 40 | jr use_defaultversion2 ; if neither major v2 or v3, who knows! use v2.53 41 | version2checkminor: 42 | ld a, (#0x0036) 43 | cp a, #0d53 ; check for v2.53 44 | jr z, use_version253 45 | cp a, #0d54 ; check for v2.54 46 | jr z, use_version254 47 | nop ; else use v2.53 anyway for now 48 | use_defaultversion2: 49 | ld a, #02 50 | ld (_firmwareversionsafe), a ; not safe firmware in use 51 | use_version253: 52 | ld hl, #0xdba1 ; set shadow vars 53 | ld (_p2shadow), hl 54 | ld hl, #0xdba2 55 | ld (_p3shadow), hl 56 | jr versioncheckcomplete 57 | use_version254: 58 | ld hl, #0xdba2 ; set shadow vars 59 | ld (_p2shadow), hl 60 | ld hl, #0xdba3 61 | ld (_p3shadow), hl 62 | jr versioncheckcomplete 63 | 64 | version3checkminor: 65 | ld a, (#0x0036) 66 | cp a, #0d3 ; check for v3.03 67 | jr z, use_version303 68 | nop ; else use v3.03 anyway for now 69 | use_defaultversion3: 70 | ld a, #0d3 71 | ld (_firmwareversionsafe), a ; not safe firmware in use 72 | use_version303: 73 | ld hl, #0xdba5 ; set shadow vars 74 | ld (_p2shadow), hl 75 | ld hl, #0xdba6 76 | ld (_p3shadow), hl 77 | jr versioncheckcomplete 78 | 79 | versioncheckcomplete: 80 | 81 | call gsinit ; Initialize global variables 82 | call _main ; Run main C code 83 | jp _exit ; Do exit procedure 84 | 85 | 86 | ;------------------------------------------------------------------------------ 87 | ; Ordering of segments for the linker. 88 | ;------------------------------------------------------------------------------ 89 | 90 | .area _HOME 91 | .area _CODE 92 | .area _GSINIT 93 | .area _GSFINAL 94 | .area _EXITPROC 95 | .area _EXITPROCFINAL 96 | .area _DATA 97 | .area _BSS 98 | .area _HEAP 99 | ;.area _CABS 100 | ;.area _OVERLAY 101 | 102 | 103 | 104 | ;------------------------------------------------------------------------------ 105 | ; Some basic code segments: __clock and _exit. 106 | ; 107 | ; No idea what __clock is, so we just return. 108 | ; 109 | ; _exit is run when your 'main' C function returns. 110 | ;------------------------------------------------------------------------------ 111 | 112 | .area _CODE 113 | 114 | ;------------------------------------------------------------------------------ 115 | 116 | __clock:: 117 | ;ld a,#2 118 | ;rst 0x08 119 | ret 120 | 121 | ;------------------------------------------------------------------------------ 122 | 123 | 124 | .area _EXITPROC 125 | _exit:: 126 | 127 | .area _EXITPROCFINAL 128 | ; restore slot4000, jump to app 129 | ld a, (startup_slot4000device) 130 | ld (#06),a 131 | ld a, (startup_slot4000page) 132 | ld (#05),a 133 | jp 0x4000 134 | 135 | ;------------------------------------------------------------------------------ 136 | 137 | 138 | 139 | 140 | ;------------------------------------------------------------------------------ 141 | ; This area is where code gets inserted automatically to inialize variables. 142 | ;------------------------------------------------------------------------------ 143 | 144 | .area _GSINIT 145 | gsinit:: 146 | .area _GSFINAL 147 | ret 148 | 149 | 150 | ;------------------------------------------------------------------------------ 151 | ; Some variables we'll need. 152 | ;------------------------------------------------------------------------------ 153 | 154 | .area _BSS 155 | 156 | startup_slot4000device: 157 | .ds 1 158 | startup_slot4000page: 159 | .ds 1 160 | _p2shadow:: 161 | .ds 2 162 | _p3shadow:: 163 | .ds 2 164 | _firmwareversionsafe:: 165 | .ds 1 166 | 167 | -------------------------------------------------------------------------------- /src/demos/FyOS/v0.01/fyos.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "mailstation.h" 4 | #include "fyos.h" 5 | 6 | unsigned char myglobal = 100; 7 | unsigned char inputstring[256]; 8 | unsigned char lastinputstring[256]; 9 | 10 | 11 | 12 | 13 | void cmd_peek(char *inputstring) 14 | { 15 | char *result = NULL; 16 | unsigned char *mempointer = 0; 17 | unsigned int hexint; 18 | int parmnum = 0; 19 | 20 | result = strtok(inputstring, " "); 21 | while (result != NULL) 22 | { 23 | parmnum++; 24 | hexint = 0; 25 | if (hextoint(result, &hexint) == 1) printf("%s -> %x\n", result, mempointer[hexint]); 26 | else printf("Invalid hex: %s\n", result); 27 | result = strtok( NULL, " " ); 28 | } 29 | 30 | if (parmnum == 0) { printf("Usage: peek FFFF D42 F03B...\n"); } 31 | printf("\n"); 32 | } 33 | 34 | void cmd_poke(char *inputstring) 35 | { 36 | char *result = NULL; 37 | unsigned char *mempointer = 0; 38 | unsigned int hexint = 0; 39 | unsigned char hexbyte = 0; 40 | int parmnum = 0; 41 | 42 | result = strtok(inputstring, " "); 43 | while (result != NULL) 44 | { 45 | parmnum++; 46 | if (parmnum == 1) 47 | { 48 | hexint = 0; 49 | if (hextoint(result, &hexint) == 1) mempointer = (unsigned char *)hexint; 50 | else { printf("Invalid address: %s\n\n", result); return; } 51 | } 52 | if (parmnum == 2) 53 | { 54 | hexbyte = 0; 55 | if (hextobyte(result, &hexbyte) == 1) *mempointer = hexbyte; 56 | else { printf("Invalid data byte: %s\n\n", result); return; } 57 | } 58 | result = strtok( NULL, " " ); 59 | } 60 | 61 | if (parmnum == 0) { printf("Usage: poke ABCD E1\n"); } 62 | else printf("%x -> %x\n", hexint, hexbyte); 63 | printf("\n"); 64 | } 65 | 66 | 67 | 68 | void cmd_hextoint(char *inputstring) 69 | { 70 | char *result = NULL; 71 | unsigned int hexint; 72 | int parmnum = 0; 73 | 74 | result = strtok(inputstring, " "); 75 | while (result != NULL) 76 | { 77 | parmnum++; 78 | hexint = 0; 79 | if (hextoint(result, &hexint) == 1) printf("%s -> %u\n", result, hexint); 80 | else printf("Invalid hex: %s\n", result); 81 | result = strtok( NULL, " " ); 82 | } 83 | 84 | if (parmnum == 0) { printf("Usage: hextoint FFC 422A 3B...\n"); } 85 | printf("\n"); 86 | } 87 | 88 | 89 | 90 | void cmd_help(char *helpcommand) 91 | { 92 | if (strlen(helpcommand) < 1) 93 | { 94 | printf("Available commands:\n\n"); 95 | printf(" CLS, EXIT, HELP, HEXTOINT, PEEK, POKE,\n POWERDOWN, REBOOT, RESET\n\n"); 96 | printf("Use HELP for more info.\n\n"); 97 | return; 98 | } 99 | strtolower(helpcommand); 100 | if (strcmp(helpcommand, "cls") == 0) printf("CLS clears the screen.\n\n"); 101 | else if (strcmp(helpcommand, "exit") == 0) printf("EXIT launches original page4000 loader.\n\n"); 102 | else if (strcmp(helpcommand, "help") == 0) printf("You're looking at it.\n\n"); 103 | else if (strcmp(helpcommand, "hextoint") == 0) printf("HEXTOINT displays hex strings as\n integers.\n\n"); 104 | else if (strcmp(helpcommand, "peek") == 0) printf("PEEK displays memory locations in hex.\n\n"); 105 | else if (strcmp(helpcommand, "poke") == 0) printf("POKE writes a byte to a memory location.\n\n"); 106 | else if (strcmp(helpcommand, "reset") == 0) printf("RESET resets FyOS to initial screen.\n\n"); 107 | else if (strcmp(helpcommand, "restart") == 0) printf("RESTART jumps to FyOS init at 0x8000.\n\n"); 108 | else if (strcmp(helpcommand, "reboot") == 0) printf("REBOOT resets the Mailstation to 0x0000.\n\n"); 109 | else if (strcmp(helpcommand, "powerdown") == 0) printf("POWERDOWN turns off the Mailstation\n via firmware function 0x0A6B.\n\n"); 110 | else printf("Unknown command: %s\n", helpcommand); 111 | 112 | } 113 | 114 | 115 | int main() 116 | { 117 | unsigned int timer = 0; 118 | unsigned int gotkey = 0; 119 | char *stringpointer = NULL; 120 | 121 | cursorx = 0; 122 | cursory = 0; 123 | 124 | __asm 125 | call #0x0AA0 ; init_keyboard, prolly not necessary, but clears out prior keypresses 126 | ;call #0x0A9D ; init_keybuffer 127 | __endasm; 128 | 129 | resetprogram: 130 | clrscr(); 131 | printfcenter("FyOS v0.01\n by FyberOptic\n \n"); 132 | printf("Mailstation firmware: v%d.%d\n", versionpointer[1], versionpointer[0]); 133 | if (firmwareversionsafe == 0) printf("Version safe: yes\n\n"); 134 | else if (firmwareversionsafe == 2) printf("Version safe: no, defaulting to v2.53\n\n"); 135 | else if (firmwareversionsafe == 3) printf("Version safe: no, defaulting to v3.03\n\n"); 136 | 137 | printf("Global var init test: "); 138 | if (myglobal == 100) printf("Pass"); 139 | else printf("Fail"); 140 | 141 | printf("\nP2shadow: %x\nP3shadow: %x\ncgafont_addr: %x\n\n", p2shadow, p3shadow, cgafont_addr); 142 | //printf("This is a test of a really long string on the screen. It should probably wrap around since it's using my original assembly code.\n\n"); 143 | 144 | 145 | commandloop: 146 | printf(">"); gets(inputstring); 147 | if (inputstring[0] == '\0') goto commandloop; 148 | strncpy(lastinputstring, inputstring, 255); 149 | 150 | stringpointer = strtok(inputstring, " "); // separate command 151 | if (stringpointer == NULL) stringpointer = inputstring; 152 | 153 | if (strcmp(stringpointer, "reset") == 0) goto resetprogram; 154 | else if (strcmp(stringpointer, "exit") == 0) goto endprogram; 155 | else if (strcmp(stringpointer, "hextoint") == 0) { cmd_hextoint(strtok(NULL, "\0")); goto commandloop; } 156 | else if (strcmp(stringpointer, "clrscr") == 0) { clrscr(); goto commandloop; } 157 | else if (strcmp(stringpointer, "cls") == 0) { clrscr(); goto commandloop; } 158 | else if (strcmp(stringpointer, "peek") == 0) { cmd_peek(strtok(NULL, "\0")); goto commandloop; } 159 | else if (strcmp(stringpointer, "poke") == 0) { cmd_poke(strtok(NULL, "\0")); goto commandloop; } 160 | else if (strcmp(stringpointer, "help") == 0) { cmd_help(strtok(NULL, "\0")); goto commandloop; } 161 | else if (strcmp(stringpointer, "powerdown") == 0) { powerdownmode(); goto commandloop; } 162 | else if (strcmp(stringpointer, "restart") == 0) 163 | { 164 | __asm 165 | jp 0x8000 166 | __endasm; 167 | } 168 | else if (strcmp(stringpointer, "reboot") == 0) 169 | { 170 | __asm 171 | jp 0x0000 172 | __endasm; 173 | } 174 | else 175 | { 176 | printf("Unknown command: %s\n\n", inputstring); 177 | goto commandloop; 178 | } 179 | 180 | 181 | endprogram: 182 | clrscr(); 183 | printf("\n\n\n\n\n\n\n\n Waiting for transfer..."); 184 | return 0; 185 | 186 | } 187 | -------------------------------------------------------------------------------- /src/tools/msloader/dump.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | /* Copyright (c) 2020 KBEmbedded */ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | /* mslib headers */ 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "dump.h" 20 | #include "interface.h" 21 | #include "parport_method.h" 22 | #include "msloader.h" 23 | 24 | #include "trampoline.bin.h" 25 | #include "LDR.bin.h" 26 | 27 | const struct opt_tbl dump_opts[] = { 28 | { " Dump Dataflash (512 KiB) to parallel port\n", dump_dflash }, 29 | { " Dump Codeflash (1 MiB) to parallel port\n", dump_cflash }, 30 | { NULL, NULL }, 31 | }; 32 | 33 | const struct opt_tbl send_opts[] = { 34 | { " Send self to parallel port with executable trampoline @ 0x8000\n", send_self_run_8000 }, 35 | { " Send self to parallel port\n", send_self_run_4000 }, 36 | { " Send app/channel 0 to parallel port\n", send_0 }, 37 | { " Send app/channel 1 to parallel port\n", send_1 }, 38 | { " Send app/channel 2 to parallel port\n", send_2 }, 39 | { " Send app/channel 3 to parallel port\n", send_3 }, 40 | { " Send app/channel 4 to parallel port\n", send_4 }, 41 | { NULL, NULL }, 42 | }; 43 | 44 | void dump_to_parport(void) 45 | { 46 | cur_opts = dump_opts; 47 | draw_header(); 48 | draw_options(); 49 | } 50 | 51 | void send_to_parport(void) 52 | { 53 | cur_opts = send_opts; 54 | draw_header(); 55 | draw_options(); 56 | printf("\nSend data to another MailStation, connected via LapLink cable.\n"); 57 | printf("This includes the 2 byte header indicating size, however, for all options\n"); 58 | printf("16384 bytes will be used since it cannot easily be known the actual size\n"); 59 | printf("of the contents of self or the app/channel.\n"); 60 | } 61 | 62 | void dump_pages(uint8_t pagecnt) 63 | { 64 | uint8_t page; 65 | uint8_t *adr; 66 | 67 | for (page = 0; page < pagecnt; page++) { 68 | SLOT8_PAGE = page; 69 | for (adr = (uint8_t *)0x8000; adr < (uint8_t *)0xC000; adr++) { 70 | if (!(*parport_write_ptr)(*adr)) { 71 | printf("Timed out!\n"); 72 | goto dump_pages_out; 73 | } 74 | } 75 | } 76 | 77 | printf("Done!\n"); 78 | 79 | dump_pages_out: 80 | lcd_update(); 81 | msfw_delay(5000); 82 | __asm__ ("jp 0x4000"); 83 | } 84 | 85 | void dump_dflash(void) 86 | { 87 | g_textmode_init(); 88 | printf("Dumping full dataflash ROM (512 KiB) over parallel port\n"); 89 | lcd_update(); 90 | 91 | SLOT8_DEV = DEV_DF; 92 | dump_pages(32); 93 | } 94 | 95 | void dump_cflash(void) 96 | { 97 | g_textmode_init(); 98 | printf("Dumping full codeflash ROM (1 MiB) over parallel port\n"); 99 | lcd_update(); 100 | 101 | SLOT8_DEV = DEV_CF; 102 | dump_pages(64); 103 | } 104 | 105 | static void send_common(void) 106 | { 107 | uint8_t *adr; 108 | 109 | /* Send 16385 as the byte count, LSB first */ 110 | if (!(*parport_write_ptr)(0x00)) { 111 | printf("Timed out!\n"); 112 | goto send_out; 113 | } 114 | 115 | if (!(*parport_write_ptr)(0x40)) { 116 | printf("Timed out!\n"); 117 | goto send_out; 118 | } 119 | 120 | for (adr = (uint8_t *)0x8000; adr < (uint8_t *)0xC000; adr++) { 121 | if (!(*parport_write_ptr)(*adr)) { 122 | printf("Timed out!\n"); 123 | goto send_out; 124 | } 125 | } 126 | 127 | send_out: 128 | lcd_update(); 129 | msfw_delay(5000); 130 | __asm__ ("jp 0x4000"); 131 | } 132 | 133 | void send_self_run_8000(void) 134 | { 135 | uint16_t adr; 136 | uint16_t end; 137 | 138 | g_textmode_init(); 139 | printf("Sending self out parallel port w/ trampoline header\n\n"); 140 | printf("On new MS, hold Fn+Shift+t (most), Fn+d, Fn+Shift+Size, Fn+Size+t, or Fn+q+a\n"); 141 | printf("(type aq781206 @ prompt) and power on. Press Shift+F5 in Diag. menu\n"); 142 | printf("Edit hex with g 710304x Back, Fn+s to enter/save&exit edit mode\n\n"); 143 | printf("Write following bytes at 0x020000: 01 00 00 00 00 00 00 00 00 18\n\n"); 144 | printf("Write the following bytes starting at 0x000000\n\n"); 145 | for (end = 0; end < LDR_bin_len; ) { 146 | printf("%02X ", LDR_bin[end]); 147 | end++; 148 | if (!(end % 8)) printf(" "); 149 | if (!(end % 16)) putchar('\n'); 150 | } 151 | printf("\nWARNING! This may clobber valid apps, see MailStation wiki for more info!"); 152 | printf("\n\nPress any key to start transfer"); 153 | lcd_update(); 154 | kbd_flush(); 155 | kbd_anykey(); 156 | g_textmode_init(); 157 | printf("Sending...\n"); 158 | lcd_update(); 159 | 160 | /* XXX: This is a repeat of send_common() code, this can probably be 161 | * trimmed down to save space */ 162 | 163 | /* Send 16385 as the byte count, LSB first */ 164 | if (!(*parport_write_ptr)(0x00)) { 165 | printf("Timed out writing low sz byte!\n"); 166 | goto self_out; 167 | } 168 | 169 | if (!(*parport_write_ptr)(0x40)) { 170 | printf("Timed out writing high sz byte!\n"); 171 | goto self_out; 172 | } 173 | 174 | // XXX: Both of these appear to be broken! 175 | // rewrite with a better loop thats not doing stupid pointer things 176 | 177 | /* Send out the trampoline header */ 178 | printf("Sending 0x%04X header bytes\n", trampoline_bin_len ); 179 | lcd_update(); 180 | for (adr = 0; adr < trampoline_bin_len; adr++) { 181 | if (!(*parport_write_ptr)(trampoline_bin[adr])) { 182 | printf("Timed out writing dat byte 0x%04X!\n", adr); 183 | goto self_out; 184 | } 185 | } 186 | 187 | /* Prep to followup and transfer self */ 188 | /* Whatever device is mapped to SLOT4, remap to SLOT8 and then 189 | * send that out. */ 190 | SLOT8_DEV = SLOT4_DEV; 191 | SLOT8_PAGE = SLOT4_PAGE; 192 | adr = 0x8000; 193 | end = adr + 0x4000 - trampoline_bin_len; 194 | printf("Sending 0x%04X more bytes\n", end - adr); 195 | lcd_update(); 196 | for (; adr < end; adr++) { 197 | if (!(*parport_write_ptr)(*(uint8_t *)adr)) { 198 | printf("Timed out writing dat byte 0x%04x!\n", adr); 199 | goto self_out; 200 | } 201 | } 202 | 203 | self_out: 204 | lcd_update(); 205 | msfw_delay(5000); 206 | __asm__ ("jp 0x4000"); 207 | } 208 | 209 | void send_self_run_4000(void) 210 | { 211 | g_textmode_init(); 212 | printf("Sending data out parallel port\n"); 213 | lcd_update(); 214 | 215 | /* Whatever device is mapped to SLOT4, remap to SLOT8 and then 216 | * send that out. */ 217 | SLOT8_DEV = SLOT4_DEV; 218 | SLOT8_PAGE = SLOT4_PAGE; 219 | send_common(); 220 | } 221 | 222 | void send_0(void) 223 | { 224 | g_textmode_init(); 225 | printf("Sending data out parallel port\n"); 226 | lcd_update(); 227 | 228 | SLOT8_DEV = DEV_DF; 229 | SLOT8_PAGE = 0; 230 | send_common(); 231 | } 232 | 233 | void send_1(void) 234 | { 235 | g_textmode_init(); 236 | printf("Sending data out parallel port\n"); 237 | lcd_update(); 238 | 239 | SLOT8_DEV = DEV_DF; 240 | SLOT8_PAGE = 1; 241 | send_common(); 242 | } 243 | 244 | void send_2(void) 245 | { 246 | g_textmode_init(); 247 | printf("Sending data out parallel port\n"); 248 | lcd_update(); 249 | 250 | SLOT8_DEV = DEV_DF; 251 | SLOT8_PAGE = 2; 252 | send_common(); 253 | } 254 | 255 | void send_3(void) 256 | { 257 | g_textmode_init(); 258 | printf("Sending data out parallel port\n"); 259 | lcd_update(); 260 | 261 | SLOT8_DEV = DEV_DF; 262 | SLOT8_PAGE = 3; 263 | send_common(); 264 | } 265 | 266 | void send_4(void) 267 | { 268 | g_textmode_init(); 269 | printf("Sending data out parallel port\n"); 270 | lcd_update(); 271 | 272 | SLOT8_DEV = DEV_DF; 273 | SLOT8_PAGE = 4; 274 | send_common(); 275 | } 276 | -------------------------------------------------------------------------------- /src/demos/FyOS/v0.01/mailstation.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "mailstation.h" 4 | 5 | 6 | ///////////////////////////////////////////////// 7 | // Simply calls the mailstation firmware's 8 | // function at 0x0A6B to power down the unit. 9 | ///////////////////////////////////////////////// 10 | void powerdownmode() 11 | { 12 | __asm 13 | call #0x0A6B ; Mailstation firmware powerdownmode function 14 | __endasm; 15 | } 16 | 17 | 18 | ///////////////////////////////////////////////// 19 | // Sets the LCD column address select bit. 20 | // 21 | // 0 = CAS enabled 22 | // 1 = CAS disabled 23 | ///////////////////////////////////////////////// 24 | void LCD_CAS_C(unsigned char casbit) 25 | { 26 | casbit = (casbit & 1) << 3; 27 | *p2shadow = (*p2shadow & 0xF7) | casbit; 28 | port2 = *p2shadow; 29 | } 30 | 31 | 32 | 33 | ///////////////////////////////////////////////// 34 | // Clears text buffer + LCD. Needs to be redone 35 | // in assembly for better speed. 36 | ///////////////////////////////////////////////// 37 | void clrscr() 38 | { 39 | unsigned char slot4000device_old = slot4000device; 40 | unsigned char *p4038 = &mem4000 + 0x38; 41 | int colnum; 42 | 43 | cursorx = 0; 44 | cursory = 0; 45 | memset(textmodebuffer, 0, 640); 46 | 47 | slot4000device = device_LCD_left; 48 | 49 | clearagain: 50 | for (colnum = 0; colnum < 20; colnum++) 51 | { 52 | LCD_CAS_C(0); 53 | *p4038 = colnum; 54 | LCD_CAS_C(1); 55 | memset(p4038, 0, 128); 56 | } 57 | if (slot4000device == device_LCD_left) { slot4000device = device_LCD_right; goto clearagain; } 58 | 59 | slot4000device = slot4000device_old; 60 | } 61 | 62 | 63 | /////////////////////////////////////////////////////////// 64 | // The following two functions were used for testing 65 | // purposes early on. getchar works now so there's not 66 | // a lot of reason to need these at the moment. getch 67 | // waits for a scancode then returns with it in the 68 | // mycharbuffer variable, while getscancode returns 69 | // immediately, placing "255" in the key state byte of 70 | // mycharbuffer (second byte) if no scancode returned. 71 | /////////////////////////////////////////////////////////// 72 | /*volatile unsigned char mycharbuffer[2]; 73 | unsigned char getch() 74 | { 75 | mycharbuffer[1] = 0; 76 | 77 | _asm 78 | push af 79 | push de 80 | ; wait till a key is available 81 | keyagain: 82 | ld de, #_mycharbuffer 83 | push de 84 | call #0x0A9A ; getkeycodefrombuffer 85 | pop de 86 | jp z, keyagain 87 | ld a, (_mycharbuffer + 1) 88 | or a 89 | jr z, keyagain 90 | pop de 91 | pop af 92 | _endasm; 93 | 94 | return mycharbuffer[0]; 95 | }*/ 96 | 97 | /*unsigned char getscancode() 98 | { 99 | //mycharbuffer[1] = 255; 100 | 101 | _asm 102 | ; wait till a key is available 103 | ld de, #_mycharbuffer 104 | push de 105 | call #0x0A9A ; v3.03a firmware getkeycodefrombuffer 106 | pop de 107 | jr nz, endgetscancode 108 | ld a, #0d255 109 | ld (_mycharbuffer + 1), a 110 | endgetscancode: 111 | _endasm; 112 | 113 | return mycharbuffer[1]; 114 | 115 | }*/ 116 | 117 | 118 | ///////////////////////////////////////////////// 119 | // Works like putchar except lets you specify 120 | // x/y coordinates to place it at. 121 | ///////////////////////////////////////////////// 122 | void putcharXY(unsigned char x, unsigned char y, unsigned char c) 123 | { 124 | unsigned char oldx, oldy; 125 | oldx = cursorx; 126 | oldy = cursory; 127 | 128 | cursorx = x; 129 | cursory = y; 130 | putchar(c); 131 | 132 | cursorx = oldx; 133 | cursory = oldy; 134 | } 135 | 136 | 137 | ///////////////////////////////////////////////// 138 | // Works just like printf, except lets you 139 | // specify x/y coordinates to place it at. 140 | ///////////////////////////////////////////////// 141 | void printfXY(unsigned char x, unsigned char y, char *xystring, ...) 142 | { 143 | unsigned char oldx, oldy; 144 | va_list args; 145 | 146 | oldx = cursorx; 147 | oldy = cursory; 148 | cursorx = x; 149 | cursory = y; 150 | 151 | va_start( args, xystring ); 152 | vprintf( xystring, args ); 153 | va_end( args ); 154 | //printf(xystring, stringvars); 155 | 156 | cursorx = oldx; 157 | cursory = oldy; 158 | } 159 | 160 | 161 | ///////////////////////////////////////////////// 162 | // Works just like printf, except centers the 163 | // string(s). Can deal with line feeds, but 164 | // multiple line feeds must at least be sep- 165 | // arated by a space character. 166 | ///////////////////////////////////////////////// 167 | void printfcenter(char *centerstring, ...) 168 | { 169 | va_list args; 170 | char tempstring[255]; 171 | char *result = NULL; 172 | 173 | va_start( args, centerstring ); 174 | vsprintf(tempstring, centerstring, args); 175 | va_end( args ); 176 | 177 | result = strtok(tempstring, "\n"); 178 | while (result != NULL) 179 | { 180 | cursorx = (40 - strlen(result)) / 2; 181 | printf("%s\n", result); 182 | result = strtok( NULL, "\n" ); 183 | } 184 | 185 | 186 | } 187 | 188 | 189 | 190 | ///////////////////////////////////////////////// 191 | // Converts the single hex character into its 192 | // numeric equivalent. Returns -1 if not a 193 | // valid hex byte. 194 | ///////////////////////////////////////////////// 195 | int hex_nibble (char x) 196 | { 197 | if (x >= '0' && x <= '9') return x - '0'; 198 | if (x >= 'a' && x <= 'f') return x - 'a' + 10; 199 | if (x >= 'A' && x <= 'F') return x - 'A' + 10; 200 | return -1; 201 | } 202 | 203 | 204 | ///////////////////////////////////////////////// 205 | // Takes hexstring and converts it into an 206 | // unsigned integer, placing it at the location 207 | // pointed to by hexint. Returns -1 if an 208 | // invalid character is found. 209 | ///////////////////////////////////////////////// 210 | char hextoint(char *hexstring, unsigned int *hexint) 211 | { 212 | unsigned int tempint = 0; 213 | char tempnibble; 214 | unsigned int n; 215 | 216 | for (n = 0; n < strlen(hexstring); n++) 217 | { 218 | tempnibble = hex_nibble(hexstring[n]); 219 | if (tempnibble == -1) return -1; 220 | tempint = tempint << 4; 221 | tempint |= tempnibble; 222 | } 223 | *hexint = tempint; 224 | return 1; 225 | } 226 | 227 | 228 | ///////////////////////////////////////////////// 229 | // Takes hexstring and converts it into an 230 | // unsigned char, placing it at the location 231 | // pointed to by hexbyte. Returns -1 if an 232 | // invalid character is found. 233 | ///////////////////////////////////////////////// 234 | char hextobyte(char *hexstring, unsigned char *hexbyte) 235 | { 236 | unsigned int tempbyte = 0; 237 | char tempnibble; 238 | unsigned int n; 239 | 240 | for (n = 0; n < strlen(hexstring); n++) 241 | { 242 | tempnibble = hex_nibble(hexstring[n]); 243 | if (tempnibble == -1) return -1; 244 | tempbyte = tempbyte << 4; 245 | tempbyte |= tempnibble; 246 | } 247 | *hexbyte = tempbyte; 248 | return 1; 249 | } 250 | 251 | 252 | 253 | ///////////////////////////////////////////////// 254 | // Reads a string from the console into s, and 255 | // returns pointer to same . This function 256 | // was taken from SDCC's SRC directory. 257 | ///////////////////////////////////////////////// 258 | char * gets(char *s) { 259 | char c; 260 | unsigned int count=0; 261 | 262 | while (1) { 263 | c=getchar(); 264 | switch(c) { 265 | case '\b': // backspace 266 | if (count) { 267 | putchar ('\b'); 268 | putchar (' '); 269 | putchar ('\b'); 270 | s--; 271 | count--; 272 | } 273 | break; 274 | case '\n': 275 | case '\r': // CR or LF 276 | putchar('\r'); 277 | putchar('\n'); 278 | *s=0; 279 | return s; 280 | default: 281 | *s++=c; 282 | count++; 283 | putchar(c); 284 | break; 285 | } 286 | } 287 | } 288 | 289 | ///////////////////////////////////////////////// 290 | // Returns 1 if parameter is uppercase, 0 if not 291 | ///////////////////////////////////////////////// 292 | char isupper(char upperchar) 293 | { 294 | if (upperchar >= 65 && upperchar <= 90) return 1; 295 | return 0; 296 | } 297 | 298 | 299 | ///////////////////////////////////////////////// 300 | // Converts a single character to lowercase, 301 | // returns the result. 302 | ///////////////////////////////////////////////// 303 | char tolower(char upperchar) 304 | { 305 | if (isupper(upperchar)) return upperchar + 32; 306 | else return upperchar; 307 | } 308 | 309 | 310 | ///////////////////////////////////////////////// 311 | // Converts an entire string to uppercase. 312 | ///////////////////////////////////////////////// 313 | void strtolower(char *upperstring) 314 | { 315 | char *stringpointer = upperstring; 316 | 317 | while (*stringpointer != 0) 318 | { 319 | *stringpointer = tolower(*stringpointer); 320 | stringpointer++; 321 | } 322 | } 323 | 324 | -------------------------------------------------------------------------------- /src/tools/msloader/save.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | /* Copyright (c) 2020 KBEmbedded */ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | /* mslib headers */ 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "interface.h" 19 | #include "loadrun.h" 20 | #include "save.h" 21 | 22 | const struct opt_tbl loadsave_opts[] = { 23 | { " Load binary and write to Channel 0 (limited to single 16kbyte page)\n", loadsave_to_0 }, 24 | { " Load binary and write to Channel 1 (limited to single 16kbyte page)\n", loadsave_to_1 }, 25 | { " Load binary and write to Channel 2 (limited to single 16kbyte page)\n", loadsave_to_2 }, 26 | { " Load binary and write to Channel 3 (limited to single 16kbyte page)\n", loadsave_to_3 }, 27 | { " Load binary and write to Channel 4 (limited to single 16kbyte page)\n", loadsave_to_4 }, 28 | { NULL, NULL }, 29 | }; 30 | 31 | const struct opt_tbl manage_dflash_opts[] = { 32 | { " Disable all Channels (CAUTION! This will disable msloader!)\n", chan_dis }, 33 | { " Enable Channel 0\n", chan_en0 }, 34 | { " Enable Channel 0-1\n", chan_en1 }, 35 | { " Enable Channel 0-2\n", chan_en2 }, 36 | { " Enable Channel 0-3\n", chan_en3 }, 37 | { " Enable Channel 0-4\n", chan_en4 }, 38 | { NULL, NULL }, 39 | }; 40 | 41 | /* Use 0 to disable all channels */ 42 | uint8_t enable_channel_max(uint8_t max) 43 | { 44 | uint8_t page, dev; 45 | uint8_t sect_buf[256]; 46 | uint8_t ret = 0; 47 | 48 | page = SLOT8_PAGE; 49 | dev = SLOT8_DEV; 50 | 51 | if (SLOT4_DEV == DEV_DF) { 52 | g_textmode_init(); 53 | printf("Error! Cannot modify channels when running from Dataflash\n"); 54 | printf("Only call enable_channel_max() when running from RAM\n"); 55 | lcd_update(); 56 | msfw_delay(5000); 57 | __asm__ ("jp 0x4000"); 58 | } 59 | 60 | SLOT8_DEV = DEV_DF; 61 | SLOT8_PAGE = 0x8; 62 | memset(sect_buf, '\0', 256); 63 | sect_buf[0x00] = max; 64 | sect_buf[0x09] = 0x18; // App 0x18 is DF 0 65 | sect_buf[0x0b] = 0x1; // DF 1 66 | sect_buf[0x0f] = 0x19; // App 0x19 is DF 1 67 | sect_buf[0x11] = 0x2; 68 | sect_buf[0x15] = 0x1a; 69 | sect_buf[0x17] = 0x3; 70 | sect_buf[0x1b] = 0x1b; 71 | sect_buf[0x1d] = 0x4; // DF 4 72 | sect_buf[0x21] = 0x1c; // App 0x1C is DF 4 73 | 74 | dflash_unlock(); 75 | ret |= dflash_erase_sector(0x8000); 76 | ret |= dflash_write_sector(0x8000, sect_buf); 77 | dflash_lock(); 78 | 79 | if (ret) { 80 | printf("Channel enable failed!\n"); 81 | } else { 82 | printf("Channel enable successful!\n"); 83 | } 84 | 85 | return ret; 86 | } 87 | 88 | void self_write_to_app0(void) 89 | { 90 | uint16_t src_adr, dst_adr; 91 | uint8_t sect_buf[256]; 92 | uint8_t ret = 0; 93 | volatile uint8_t *cur_channel = (uint8_t *)0x8000; 94 | 95 | g_textmode_init(); 96 | printf("Writing self to DF, Mailstation App 0\n"); 97 | lcd_update(); 98 | 99 | SLOT8_DEV = DEV_DF; 100 | SLOT8_PAGE = 0x0; 101 | 102 | dflash_unlock(); 103 | 104 | src_adr = 0x4000; 105 | dst_adr = 0x8000; 106 | 107 | for (; dst_adr < 0xC000; ) { 108 | ret |= dflash_erase_sector(dst_adr); 109 | memcpy(sect_buf, (volatile uint8_t *)src_adr, 256); 110 | ret |= dflash_write_sector(dst_adr, sect_buf); 111 | src_adr = src_adr + 256; 112 | dst_adr = dst_adr + 256; 113 | } 114 | 115 | dflash_lock(); 116 | 117 | SLOT8_PAGE = 0x8; // App management page 118 | /* Do this to fill out all app records */ 119 | enable_channel_max(*cur_channel); 120 | 121 | if (ret) { 122 | printf("Write failed!\n"); 123 | } else { 124 | printf("Write successful!\n"); 125 | } 126 | 127 | printf("Powering off in 5 seconds\n"); 128 | lcd_update(); 129 | msfw_delay(5000); 130 | 131 | msfw_poweroff(); 132 | } 133 | 134 | 135 | void manage_dflash(void) 136 | { 137 | cur_opts = manage_dflash_opts; 138 | draw_header(); 139 | draw_options(); 140 | } 141 | 142 | /* XXX: Problem here is that, when running from DF, we can;t really 143 | * unlock/lock DF since the pattern has to come from DF reads. 144 | * It does not appear there is a good firmware function to handle this. 145 | * From exploration it looks like the only function that really does this 146 | * in firmware does a lot more, potentially is meant to write a whole 147 | * page at a time. Which would be great if so, but, would require more 148 | * exploration. 149 | * 150 | * so... lets do a quick hack! 151 | */ 152 | static void reload_ram_trampoline(void) __naked 153 | { 154 | SLOT4_DEV = DEV_RAM; 155 | SLOT4_PAGE = 0x2; 156 | __asm__ ("ret"); 157 | } 158 | 159 | void loadsave_common(uint8_t channel) 160 | { 161 | uint8_t page, dev, ret = 0; 162 | unsigned int i; 163 | uint16_t len, dst_adr; 164 | uint8_t sect_buf[256]; 165 | uint8_t *cur_channel = (uint8_t *)0x8000; 166 | 167 | 168 | /* If we're running from RAM (possible but unlikely) then skip this 169 | * rewrite and trampoline */ 170 | if (SLOT4_DEV != DEV_RAM) { 171 | /* RAMp1 will be in slot8 if msloader is run from DF. 172 | * Rewrite ourselves to RAMp2 in slot8, then call the reload 173 | * trampoline to put RAMp2 in slot4 and return back to this 174 | * func. The result is changing execution to slot4 but RAM to 175 | * preven spurious DF read patterns during unlock 176 | */ 177 | SLOT8_PAGE = 2; 178 | SLOT8_DEV = DEV_RAM; 179 | memcpy((uint8_t *)0x8000, (uint8_t *)0x4000, 0x4000); 180 | 181 | /* Clobber all of our graphics buffer, overkill, but its a known 182 | * value that needs to be kept to. It beats trying to calculate the 183 | * exact length of our trampoline. 184 | */ 185 | memcpy((uint8_t *)0xC010, reload_ram_trampoline, 0x1400); 186 | __asm__ ("call 0xC010"); 187 | 188 | /* At this point, we... should be back to this function, still 189 | * running from slot4, but from RAM rather than DF. Move RAMp1 190 | * in to slot8 for working RAM */ 191 | /* XXX: Should we save slot8 context above and restore it? */ 192 | SLOT8_PAGE = 1; 193 | SLOT8_DEV = DEV_RAM; 194 | } 195 | 196 | g_textmode_init(); 197 | 198 | /* Lets use display buffer because why not */ 199 | /* TODO: Save slot and do something? */ 200 | len = load_from_parport((volatile uint8_t *)0x8000); 201 | if (!len) { 202 | printf("Error! Loading timed out / no data received!\n"); 203 | lcd_update(); 204 | msfw_delay(5000); 205 | __asm__("jp 0x4000"); 206 | } 207 | page = SLOT8_PAGE; 208 | dev = SLOT8_DEV; 209 | 210 | if (len & 0xFF) len = (len & ~(0xff)) + 0x100; 211 | /* Write the length of the file to DF channel */ 212 | len = (len / 256); 213 | lcd_update(); 214 | msfw_delay(2000); 215 | 216 | for (i = 0; i < len; i++) { 217 | dst_adr = (0x8000 + (i * 0x100)); 218 | /* Copy 256 bytes to display buffer RAM */ 219 | memcpy(sect_buf, (volatile uint8_t *)dst_adr, 0x100); 220 | 221 | /* Set up the correct channel page, erase sector, and write 222 | * data from display butter to DF */ 223 | SLOT8_PAGE = channel; 224 | SLOT8_DEV = DEV_DF; 225 | dflash_unlock(); 226 | ret |= dflash_erase_sector(dst_adr); 227 | ret |= dflash_write_sector(dst_adr, sect_buf); 228 | lcd_update(); 229 | dflash_lock(); 230 | SLOT8_PAGE = page; 231 | SLOT8_DEV = dev; 232 | } 233 | 234 | SLOT8_DEV = DEV_DF; 235 | SLOT8_PAGE = 8; 236 | /* While channels are numbered 0-4, the number of enabled channels 237 | * is 0-5, with 0 being none and 1 being only channel 0. */ 238 | channel++; 239 | if (channel > *cur_channel) { 240 | ret |= enable_channel_max(channel); 241 | } 242 | 243 | 244 | if (ret) { 245 | printf("Write of new app failed!\n"); 246 | } else { 247 | printf("Write of new app successful!\n"); 248 | } 249 | 250 | printf("Powering off in 5 seconds\n"); 251 | lcd_update(); 252 | msfw_delay(5000); 253 | msfw_poweroff(); 254 | } 255 | 256 | void loadsave_to_0(void) 257 | { 258 | g_textmode_init(); 259 | printf("Loading binary and saving to Channel/App 0\n"); 260 | lcd_update(); 261 | loadsave_common(0); 262 | } 263 | 264 | void loadsave_to_1(void) 265 | { 266 | g_textmode_init(); 267 | printf("Loading binary and saving to Channel/App 1\n"); 268 | lcd_update(); 269 | loadsave_common(1); 270 | } 271 | 272 | void loadsave_to_2(void) 273 | { 274 | g_textmode_init(); 275 | printf("Loading binary and saving to Channel/App 2\n"); 276 | lcd_update(); 277 | loadsave_common(2); 278 | } 279 | 280 | void loadsave_to_3(void) 281 | { 282 | g_textmode_init(); 283 | printf("Loading binary and saving to Channel/App 3\n"); 284 | lcd_update(); 285 | loadsave_common(3); 286 | } 287 | 288 | void loadsave_to_4(void) 289 | { 290 | g_textmode_init(); 291 | printf("Loading binary and saving to Channel/App 4\n"); 292 | lcd_update(); 293 | loadsave_common(4); 294 | } 295 | 296 | void chan_en_common(uint8_t max) 297 | { 298 | uint8_t ret; 299 | 300 | /* XXX: I _think_ that RAMp1 is always in slot8 when launching DF app 301 | * need to verify this. 302 | * Set up slot8 to be page 1 of RAM. We're going to rewrite ourself 303 | * there, do the trampoline to move that in slot4, and then set 304 | * slot8 to be RAMp2 for the actual loading process. 305 | */ 306 | SLOT8_PAGE = 2; 307 | SLOT8_DEV = DEV_RAM; 308 | memcpy((uint8_t *)0x8000, (uint8_t *)0x4000, 0x4000); 309 | 310 | /* Clobber all of our graphics buffer, overkill, but its a known 311 | * value that needs to be kept to. It beats trying to calculate the 312 | * exact length of our trampoline. 313 | */ 314 | memcpy((uint8_t *)0xC010, reload_ram_trampoline, 0x1400); 315 | __asm__ ("call 0xC010"); 316 | 317 | g_textmode_init(); 318 | ret = enable_channel_max(max); 319 | 320 | if (ret) { 321 | printf("Channel management failed!\n"); 322 | } else { 323 | printf("Channel management successful!\n"); 324 | } 325 | 326 | lcd_update(); 327 | msfw_delay(5000); 328 | __asm__("jp 0x4000"); 329 | } 330 | 331 | void chan_dis(void) 332 | { 333 | chan_en_common(0); 334 | } 335 | 336 | void chan_en0(void) 337 | { 338 | chan_en_common(1); 339 | } 340 | 341 | void chan_en1(void) 342 | { 343 | chan_en_common(2); 344 | } 345 | 346 | void chan_en2(void) 347 | { 348 | chan_en_common(3); 349 | } 350 | 351 | void chan_en3(void) 352 | { 353 | chan_en_common(4); 354 | } 355 | 356 | void chan_en4(void) 357 | { 358 | chan_en_common(5); 359 | } 360 | 361 | void loadsave_from_parport(void) 362 | { 363 | cur_opts = loadsave_opts; 364 | draw_header(); 365 | draw_options(); 366 | } 367 | -------------------------------------------------------------------------------- /src/demos/FyOS/v0.02/fyos.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "mailstation.h" 4 | #include "fyos.h" 5 | 6 | unsigned char inputstring[256]; 7 | unsigned char myglobal = 100; 8 | //unsigned char lastinputstring[256]; 9 | 10 | 11 | void cmd_peek(char *inputstring) 12 | { 13 | char *result = NULL; 14 | unsigned char *mempointer = 0; 15 | unsigned int hexint; 16 | int parmnum = 0; 17 | 18 | result = strtok(inputstring, " "); 19 | while (result != NULL) 20 | { 21 | parmnum++; 22 | hexint = 0; 23 | if (hextoint(result, &hexint) == 1) printf("%04x -> %02x\n", hexint, mempointer[hexint]); 24 | else printf("Invalid hex: %s\n", result); 25 | result = strtok( NULL, " " ); 26 | } 27 | 28 | if (parmnum == 0) { printf("Usage: peek FFFF D42 F03B...\n"); } 29 | printf("\n"); 30 | } 31 | 32 | void cmd_poke(char *inputstring) 33 | { 34 | char *result = NULL; 35 | unsigned char *mempointer = 0; 36 | unsigned int hexint = 0; 37 | unsigned char hexbyte = 0; 38 | int parmnum = 0; 39 | 40 | result = strtok(inputstring, " "); 41 | while (result != NULL) 42 | { 43 | parmnum++; 44 | if (parmnum == 1) 45 | { 46 | hexint = 0; 47 | if (hextoint(result, &hexint) == 1) mempointer = (unsigned char *)hexint; 48 | else { printf("Invalid address: %s\n\n", result); return; } 49 | } 50 | if (parmnum == 2) 51 | { 52 | hexbyte = 0; 53 | if (hextobyte(result, &hexbyte) == 1) *mempointer = hexbyte; 54 | else { printf("Invalid data byte: %s\n\n", result); return; } 55 | } 56 | result = strtok( NULL, " " ); 57 | } 58 | 59 | if (parmnum == 0) { printf("Usage: poke ABCD E1\n"); } 60 | else printf("%04x -> %02x\n", hexint, hexbyte); 61 | printf("\n"); 62 | } 63 | 64 | 65 | 66 | void cmd_port_in(char *inputstring) 67 | { 68 | char *result = NULL; 69 | unsigned char *mempointer = 0; 70 | unsigned int hexint = 0; 71 | volatile unsigned char hexbyte = 0; 72 | int parmnum = 0; 73 | 74 | result = strtok(inputstring, " "); 75 | while (result != NULL) 76 | { 77 | parmnum++; 78 | hexint = 0; 79 | hexbyte = 0; 80 | if (hextoint(result, &hexint) == 1) 81 | { 82 | __asm 83 | push af 84 | push bc 85 | ld c, -4(ix) ; low byte hexint 86 | ld b, -3(ix) ; high byte hexint 87 | in a, (C) 88 | ld -5(ix), a ; hexbyte 89 | pop bc 90 | pop af 91 | __endasm; 92 | printf("%04x -> %02x\n", hexint, hexbyte); 93 | } 94 | else { printf("Invalid address: %s\n\n", result); return; } 95 | result = strtok( NULL, " " ); 96 | } 97 | 98 | if (parmnum == 0) { printf("Usage: PORT_IN AB E1...\n"); } 99 | printf("\n"); 100 | } 101 | 102 | 103 | 104 | void cmd_port_out(char *inputstring) 105 | { 106 | char *result = NULL; 107 | unsigned char *mempointer = 0; 108 | unsigned int hexint = 0; 109 | unsigned char hexbyte = 0; 110 | int parmnum = 0; 111 | 112 | result = strtok(inputstring, " "); 113 | while (result != NULL) 114 | { 115 | parmnum++; 116 | if (parmnum == 1) 117 | { 118 | hexint = 0; 119 | if (hextoint(result, &hexint) == 1) {} 120 | else { printf("Invalid address: %s\n\n", result); return; } 121 | } 122 | if (parmnum == 2) 123 | { 124 | hexbyte = 0; 125 | if (hextobyte(result, &hexbyte) == 1) 126 | { 127 | __asm 128 | push af 129 | push bc 130 | ld c, -4(ix) ; low byte hexint 131 | ld b, -3(ix) ; high byte hexint 132 | ld a, -5(ix) ; hexbyte 133 | out (C), a 134 | pop bc 135 | pop af 136 | __endasm; 137 | } 138 | else { printf("Invalid data byte: %s\n\n", result); return; } 139 | } 140 | result = strtok( NULL, " " ); 141 | } 142 | 143 | if (parmnum == 0) { printf("Usage: PORT_OUT AB E1\n"); } 144 | else printf("%04x -> %02x\n", hexint, hexbyte); 145 | printf("\n"); 146 | } 147 | 148 | 149 | 150 | void cmd_hextoint(char *inputstring) 151 | { 152 | char *result = NULL; 153 | unsigned int hexint; 154 | int parmnum = 0; 155 | 156 | result = strtok(inputstring, " "); 157 | while (result != NULL) 158 | { 159 | parmnum++; 160 | hexint = 0; 161 | if (hextoint(result, &hexint) == 1) printf("%4s -> %u\n", result, hexint); 162 | else printf("Invalid hex: %s\n", result); 163 | result = strtok( NULL, " " ); 164 | } 165 | 166 | if (parmnum == 0) { printf("Usage: hextoint FFC 422A 3B...\n"); } 167 | printf("\n"); 168 | } 169 | 170 | 171 | void cmd_scancodes() 172 | { 173 | unsigned char lastkey = 0; 174 | unsigned char mycharbuffer[2]; 175 | 176 | while (getscancode(mycharbuffer) == 255) {} // get last scancodes just to clear it out 177 | 178 | printf("Press any key to show scancode, or Back to return to command prompt.\n\n"); 179 | 180 | while (lastkey != 1) 181 | { 182 | if (getscancode(mycharbuffer) != 255) 183 | { 184 | printfcenter("Scancode: %03d Key state: %03d\n", mycharbuffer[0], mycharbuffer[1]); 185 | lastkey = mycharbuffer[0]; 186 | } 187 | } 188 | printf("\n"); 189 | } 190 | 191 | 192 | void cmd_help(char *helpcommand) 193 | { 194 | // if (strlen(helpcommand) < 1) 195 | // Saves some bytes to do this instead of strlen 196 | if (helpcommand[0] == 0) 197 | { 198 | printf("Available commands:\n\n"); 199 | printf(" CLS, EXIT, HELP, HEXTOINT, PEEK, POKE,\n PORT_IN, PORT_OUT, POWERDOWN, REBOOT,\n RESET, SCANCODES\n\n"); 200 | printf("Use HELP for more info.\n\n"); 201 | return; 202 | } 203 | strtolower(helpcommand); 204 | if (strcmp(helpcommand, "cls") == 0) printf("CLS clears the screen.\n\n"); 205 | else if (strcmp(helpcommand, "exit") == 0) printf("EXIT launches original page4000 loader.\n\n"); 206 | else if (strcmp(helpcommand, "help") == 0) printf("You're looking at it.\n\n"); 207 | else if (strcmp(helpcommand, "hextoint") == 0) printf("HEXTOINT displays hex strings as\n integers.\n\n"); 208 | else if (strcmp(helpcommand, "peek") == 0) printf("PEEK displays memory locations in hex.\n\n"); 209 | else if (strcmp(helpcommand, "poke") == 0) printf("POKE writes a byte to a memory location.\n\n"); 210 | else if (strcmp(helpcommand, "port_out") == 0) printf("PORT_OUT writes a byte to a port.\n\n"); 211 | else if (strcmp(helpcommand, "port_in") == 0) printf("PORT_IN reads a byte from port(s).\n\n"); 212 | else if (strcmp(helpcommand, "reset") == 0) printf("RESET resets FyOS to initial screen.\n\n"); 213 | else if (strcmp(helpcommand, "restart") == 0) printf("RESTART jumps to FyOS init at 0x8000.\n\n"); 214 | else if (strcmp(helpcommand, "reboot") == 0) printf("REBOOT resets the Mailstation to 0x0000.\n\n"); 215 | else if (strcmp(helpcommand, "scancodes") == 0) printf("SCANCODES is an interactive key viewer.\n\n"); 216 | else if (strcmp(helpcommand, "powerdown") == 0) printf("POWERDOWN turns off the Mailstation\n via firmware function 0x0A6B.\n\n"); 217 | else printf("Unknown command: %s\n", helpcommand); 218 | } 219 | 220 | 221 | int main() 222 | { 223 | unsigned int timer = 0; 224 | unsigned int gotkey = 0; 225 | char *stringpointer = NULL; 226 | 227 | cursorx = 0; 228 | cursory = 0; 229 | 230 | /* 231 | _asm 232 | call #0x0AA0 ; init_keyboard 233 | ;call #0x0A9D ; init_keybuffer 234 | _endasm; 235 | */ 236 | 237 | resetprogram: 238 | clrscr(); 239 | printfcenter("FyOS v0.02\n by FyberOptic\n \n"); 240 | printf("Mailstation firmware: v%d.%d\n", versionpointer[1], versionpointer[0]); 241 | 242 | printf("Version safe: "); 243 | switch (firmwareversionsafe) 244 | { 245 | case 0: printf("yes"); break; 246 | case 2: printf("no, defaulting to v2.53"); break; 247 | case 3: printf("no, defaulting to v3.03"); break; 248 | default: printf("unknown"); break; 249 | } 250 | 251 | printf("\n\nGlobal var init test: "); 252 | if (myglobal == 100) printf("Pass"); 253 | else printf("Fail"); 254 | 255 | printf("\nP2shadow: %x\nP3shadow: %x\ncgafont_addr: %x\n\n", p2shadow, p3shadow, cgafont_addr); 256 | 257 | //memset(graphicsmodebuffer, 255, 5120); 258 | //UpdateGraphicsLCD(); 259 | //getchar(); 260 | 261 | commandloop: 262 | printf(">"); gets(inputstring); 263 | if (inputstring[0] == '\0') goto commandloop; 264 | //strncpy(lastinputstring, inputstring, 255); 265 | 266 | stringpointer = strtok(inputstring, " "); // separate command 267 | if (stringpointer == NULL) stringpointer = inputstring; 268 | 269 | if (strcmp(stringpointer, "reset") == 0) goto resetprogram; 270 | else if (strcmp(stringpointer, "exit") == 0) goto endprogram; 271 | else if (strcmp(stringpointer, "hextoint") == 0) { cmd_hextoint(strtok(NULL, "\0")); goto commandloop; } 272 | else if (strcmp(stringpointer, "clrscr") == 0) { clrscr(); goto commandloop; } 273 | else if (strcmp(stringpointer, "cls") == 0) { clrscr(); goto commandloop; } 274 | else if (strcmp(stringpointer, "peek") == 0) { cmd_peek(strtok(NULL, "\0")); goto commandloop; } 275 | else if (strcmp(stringpointer, "poke") == 0) { cmd_poke(strtok(NULL, "\0")); goto commandloop; } 276 | else if (strcmp(stringpointer, "port_in") == 0) { cmd_port_in(strtok(NULL, "\0")); goto commandloop; } 277 | else if (strcmp(stringpointer, "port_out") == 0) { cmd_port_out(strtok(NULL, "\0")); goto commandloop; } 278 | else if (strcmp(stringpointer, "help") == 0) { cmd_help(strtok(NULL, "\0")); goto commandloop; } 279 | else if (strcmp(stringpointer, "scancodes") == 0) { cmd_scancodes(); goto commandloop; } 280 | else if (strcmp(stringpointer, "powerdown") == 0) { powerdownmode(); goto commandloop; } 281 | else if (strcmp(stringpointer, "restart") == 0) 282 | { 283 | __asm 284 | jp 0x8000 285 | __endasm; 286 | } 287 | else if (strcmp(stringpointer, "reboot") == 0) 288 | { 289 | __asm 290 | jp 0x0000 291 | __endasm; 292 | } 293 | else 294 | { 295 | printf("Unknown command: %s\n\n", inputstring); 296 | goto commandloop; 297 | } 298 | 299 | 300 | endprogram: 301 | clrscr(); 302 | printf("\n\n\n\n\n\n\n\n Waiting for transfer..."); 303 | return 0; 304 | 305 | } 306 | -------------------------------------------------------------------------------- /src/demos/FyOS/v0.02/mailstation.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "mailstation.h" 4 | 5 | 6 | ///////////////////////////////////////////////// 7 | // Simply calls the mailstation firmware's 8 | // function at 0x0A6B to power down the unit. 9 | ///////////////////////////////////////////////// 10 | void powerdownmode() 11 | { 12 | __asm 13 | call #0x0A6B ; Mailstation firmware powerdownmode function 14 | __endasm; 15 | } 16 | 17 | 18 | ///////////////////////////////////////////////// 19 | // Sets the LCD column address select bit. 20 | // 21 | // 0 = CAS enabled 22 | // 1 = CAS disabled 23 | // 24 | // NOTE: Moved to putchar.s 25 | ///////////////////////////////////////////////// 26 | /* 27 | void LCD_CAS(unsigned char casbit) 28 | { 29 | casbit = (casbit & 1) << 3; 30 | *p2shadow = (*p2shadow & 0xF7) | casbit; 31 | port2 = *p2shadow; 32 | } 33 | */ 34 | 35 | 36 | ///////////////////////////////////////////////// 37 | // Clears text buffer + LCD. Needs to be redone 38 | // in assembly for better speed. 39 | // 40 | // NOTE: Much was optimized into the assembly 41 | // function ClearLCD() in putchar.s. 42 | ///////////////////////////////////////////////// 43 | void clrscr() 44 | { 45 | //unsigned char slot4000device_old = slot4000device; 46 | //unsigned char *p4038 = &mem4000 + 0x38; 47 | //int colnum; 48 | 49 | cursorx = 0; 50 | cursory = 0; 51 | memset(textmodebuffer, 0, 640); 52 | 53 | ClearLCD(); 54 | 55 | /* 56 | slot4000device = device_LCD_left; 57 | 58 | clearagain: 59 | for (colnum = 0; colnum < 20; colnum++) 60 | { 61 | LCD_CAS(0); 62 | *p4038 = colnum; 63 | LCD_CAS(1); 64 | memset(p4038, 0, 128); 65 | } 66 | if (slot4000device == device_LCD_left) { slot4000device = device_LCD_right; goto clearagain; } 67 | 68 | slot4000device = slot4000device_old; 69 | */ 70 | } 71 | 72 | 73 | 74 | ///////////////////////////////////////////////// 75 | // This is essentially the same function as in 76 | // the Mailstation firmware, just removed so 77 | // that it can be accessed regardless of which 78 | // firmware version is used (since the address 79 | // changes). It draws the buffer at 0xc010 to 80 | // the LCD. 81 | // 82 | // If you never plan to use it, comment it out 83 | // to save some space. 84 | // 85 | ///////////////////////////////////////////////// 86 | void UpdateGraphicsLCD() __naked 87 | { 88 | __asm 89 | push af 90 | push bc 91 | push de 92 | push hl 93 | 94 | in a, (#06) 95 | ld e, a 96 | push de 97 | ld a, #0x02 98 | out (#06), a 99 | ld hl, #0xc010 100 | call update_half 101 | ld a, #0x04 102 | out (#06), a 103 | ld hl, #0xca10 104 | call update_half 105 | pop de 106 | ld a, e 107 | out (#06), a 108 | 109 | pop hl 110 | pop de 111 | pop bc 112 | pop af 113 | ret 114 | 115 | update_half: 116 | ld b, #0x14 117 | update_half2: 118 | ld de, #0x4038 119 | 120 | push hl 121 | ld hl, (_p2shadow) 122 | ld a, (hl) 123 | and #0xF7 124 | ld (hl),a 125 | out (#02),a 126 | 127 | ld a, b 128 | dec a 129 | ld (de), a 130 | 131 | ld a, (hl) 132 | or #0x08 133 | ld (hl),a 134 | out (#02),a 135 | pop hl 136 | 137 | ld a, b 138 | ld b, #0x00 139 | ld c, #0x80 140 | ldir 141 | ld b,a 142 | djnz update_half2 143 | ret 144 | __endasm; 145 | } 146 | 147 | 148 | /////////////////////////////////////////////////////////// 149 | // Gets a scancode + key state from the Mailstation's 150 | // keyboard buffer and places the two bytes into the 151 | // specified "charbuffer" location. If no key was 152 | // returned, the key state, charbuffer[1], will be set 153 | // to 255. 154 | // 155 | // Key state bits: 156 | // 0 = Set if key was pressed, clear if key was released 157 | // 5 = Set if Caps Lock was on when key was toggled 158 | // 6 = Set if Shift was held when key was toggled 159 | // 7 = Set if Fn was held when key was toggled 160 | /////////////////////////////////////////////////////////// 161 | unsigned char getscancode(unsigned char *charbuffer) 162 | { 163 | __asm 164 | push af 165 | push hl 166 | push ix 167 | 168 | ld ix, #2 + #6 + #2 ; C-pushed ix + pushed regs + ret address 169 | add ix, sp 170 | ld l, 0x0(ix) 171 | ld h, 0x1(ix) 172 | 173 | ld a, h 174 | ld (#0xc010), a 175 | ld a, l 176 | ld (#0xc011), a 177 | 178 | push hl 179 | call #0x0A9A ; MS firmware getkeycodefrombuffer 180 | pop hl 181 | inc hl 182 | 183 | jr nz, endgetscancode 184 | ld a, #0d255 185 | ld (hl), a 186 | endgetscancode: 187 | pop ix 188 | pop hl 189 | pop af 190 | __endasm; 191 | 192 | 193 | return charbuffer[1]; 194 | } 195 | 196 | 197 | ///////////////////////////////////////////////// 198 | // Works like putchar except lets you specify 199 | // x/y coordinates to place it at. 200 | ///////////////////////////////////////////////// 201 | void putcharXY(unsigned char x, unsigned char y, unsigned char c) 202 | { 203 | unsigned char oldx, oldy; 204 | oldx = cursorx; 205 | oldy = cursory; 206 | 207 | cursorx = x; 208 | cursory = y; 209 | putchar(c); 210 | 211 | cursorx = oldx; 212 | cursory = oldy; 213 | } 214 | 215 | 216 | ///////////////////////////////////////////////// 217 | // Works just like printf, except lets you 218 | // specify x/y coordinates to place it at. 219 | ///////////////////////////////////////////////// 220 | void printfXY(unsigned char x, unsigned char y, char *xystring, ...) 221 | { 222 | unsigned char oldx, oldy; 223 | va_list args; 224 | 225 | oldx = cursorx; 226 | oldy = cursory; 227 | cursorx = x; 228 | cursory = y; 229 | 230 | va_start( args, xystring ); 231 | vprintf( xystring, args ); 232 | va_end( args ); 233 | 234 | cursorx = oldx; 235 | cursory = oldy; 236 | } 237 | 238 | 239 | ///////////////////////////////////////////////// 240 | // Works just like printf, except centers the 241 | // string(s). Can deal with line feeds, but 242 | // multiple line feeds must at least be sep- 243 | // arated by a space character. 244 | ///////////////////////////////////////////////// 245 | void printfcenter(char *centerstring, ...) 246 | { 247 | va_list args; 248 | char tempstring[255]; 249 | char *result = NULL; 250 | 251 | va_start( args, centerstring ); 252 | vsprintf(tempstring, centerstring, args); 253 | va_end( args ); 254 | 255 | result = strtok(tempstring, "\n"); 256 | while (result != NULL) 257 | { 258 | cursorx = (40 - strlen(result)) / 2; 259 | printf("%s\n", result); 260 | result = strtok( NULL, "\n" ); 261 | } 262 | } 263 | 264 | 265 | 266 | ///////////////////////////////////////////////// 267 | // Converts the single hex character into its 268 | // numeric equivalent. Returns -1 if not a 269 | // valid hex byte. 270 | ///////////////////////////////////////////////// 271 | int hex_nibble (char x) 272 | { 273 | if (x >= '0' && x <= '9') return x - '0'; 274 | if (x >= 'a' && x <= 'f') return x - 'a' + 10; 275 | if (x >= 'A' && x <= 'F') return x - 'A' + 10; 276 | return -1; 277 | } 278 | 279 | 280 | ///////////////////////////////////////////////// 281 | // Takes hexstring and converts it into an 282 | // unsigned integer, placing it at the location 283 | // pointed to by hexint. Returns -1 if an 284 | // invalid hex character is found. 285 | ///////////////////////////////////////////////// 286 | char hextoint(char *hexstring, unsigned int *hexint) 287 | { 288 | unsigned int tempint = 0; 289 | char tempnibble; 290 | unsigned int n; 291 | 292 | for (n = 0; n < strlen(hexstring); n++) 293 | { 294 | tempnibble = hex_nibble(hexstring[n]); 295 | if (tempnibble == -1) return -1; 296 | tempint <<= 4; 297 | tempint |= tempnibble; 298 | } 299 | *hexint = tempint; 300 | return 1; 301 | } 302 | 303 | 304 | ///////////////////////////////////////////////// 305 | // Takes hexstring and converts it into an 306 | // unsigned char, placing it at the location 307 | // pointed to by hexbyte. Returns -1 if an 308 | // invalid hex character is found. 309 | ///////////////////////////////////////////////// 310 | char hextobyte(char *hexstring, unsigned char *hexbyte) 311 | { 312 | unsigned int tempbyte = 0; 313 | char tempnibble; 314 | unsigned int n; 315 | 316 | for (n = 0; n < strlen(hexstring); n++) 317 | { 318 | tempnibble = hex_nibble(hexstring[n]); 319 | if (tempnibble == -1) return -1; 320 | tempbyte = tempbyte << 4; 321 | tempbyte |= tempnibble; 322 | } 323 | *hexbyte = tempbyte; 324 | return 1; 325 | } 326 | 327 | 328 | 329 | ///////////////////////////////////////////////// 330 | // Reads a string from the console into s, and 331 | // returns pointer to same . This function 332 | // was taken from SDCC's SRC directory. 333 | ///////////////////////////////////////////////// 334 | char * gets(char *s) { 335 | char c; 336 | unsigned int count=0; 337 | 338 | while (1) { 339 | c=getchar(); 340 | switch(c) { 341 | case '\b': // backspace 342 | if (count) { 343 | putchar ('\b'); 344 | putchar (' '); 345 | putchar ('\b'); 346 | s--; 347 | count--; 348 | } 349 | break; 350 | case '\n': 351 | case '\r': // CR or LF 352 | putchar('\r'); 353 | putchar('\n'); 354 | *s=0; 355 | return s; 356 | default: 357 | *s++=c; 358 | count++; 359 | putchar(c); 360 | break; 361 | } 362 | } 363 | } 364 | 365 | 366 | ///////////////////////////////////////////////// 367 | // Returns 1 if parameter is uppercase, 0 if not 368 | ///////////////////////////////////////////////// 369 | char isupper(char upperchar) 370 | { 371 | if (upperchar >= 65 && upperchar <= 90) return 1; 372 | return 0; 373 | } 374 | 375 | 376 | ///////////////////////////////////////////////// 377 | // Converts a single character to lowercase, 378 | // returns the result. 379 | ///////////////////////////////////////////////// 380 | char tolower(char upperchar) 381 | { 382 | if (isupper(upperchar)) return upperchar + 32; 383 | return upperchar; 384 | } 385 | 386 | 387 | ///////////////////////////////////////////////// 388 | // Converts an entire string to uppercase. 389 | ///////////////////////////////////////////////// 390 | void strtolower(char *upperstring) 391 | { 392 | char *stringpointer = upperstring; 393 | 394 | while (*stringpointer != 0) 395 | { 396 | *stringpointer = tolower(*stringpointer); 397 | stringpointer++; 398 | } 399 | } 400 | 401 | -------------------------------------------------------------------------------- /src/host/mailtransfer/mailtransfer.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | /* Based on work from FybderOptic (fyberoptic@gmail.com) which was based 3 | * on work from Cyrano Jones of the original Yahho! Mailstation group. */ 4 | 5 | /* Used to send binary blobs between host PC and Mailstation device. 6 | * 7 | * This was put together quickly to address a few shortcomings and unify send/ 8 | * recv to a single tool. Meant to be used in conjunction with the MS Loader 9 | * tool on the Mailstation to download or upload binary blobs of data. 10 | * 11 | * This tool is pretty rough and poorly implemented, but it should at least now 12 | * be compatible with PCIe Parallel port devices on a host that may not lie 13 | * anywhere close to the traditional IO addresses. See help for use. 14 | * 15 | * Uses inpout32.dll to interface with I/O port of the parallel interface. 16 | * This .dll is included in this repo since I have no idea where the sources 17 | * are. This is a 32-bit dll I think. 18 | * 19 | * Compilation has only been tested with 32-bit MinGW from a Linux host, e.g. 20 | * i686-w64-mingw32-gcc This should also work with a MinGW install in Windows. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | uint16_t DATA; 32 | uint16_t STATUS; 33 | uint16_t CONTROL; 34 | 35 | const unsigned char BSY_IN = 0x40; 36 | const unsigned char BSY_OUT = 0x08; 37 | const unsigned char STB_IN = 0x80; 38 | const unsigned char STB_OUT = 0x10; 39 | const unsigned char TRIBMASK = 0x07; 40 | const unsigned char DIBMASK = 0x03; 41 | 42 | typedef short (_stdcall *inpfuncPtr)(short portaddr); 43 | typedef void (_stdcall *oupfuncPtr)(short portaddr, short datum); 44 | 45 | inpfuncPtr inp32fp; 46 | oupfuncPtr oup32fp; 47 | 48 | enum operation { 49 | OP_NONE = 0, 50 | OP_SEND = 1, 51 | OP_RECV = 2 52 | }; 53 | 54 | short Inp32 (short portaddr) 55 | { 56 | return (inp32fp)(portaddr); 57 | } 58 | 59 | void Out32 (short portaddr, short datum) 60 | { 61 | (oup32fp)(portaddr,datum); 62 | } 63 | 64 | 65 | /* TODO: Figure out how to differentiate between 32 and 64bit? */ 66 | int InitIOLibrary() 67 | { 68 | HINSTANCE hLib; 69 | 70 | SetDllDirectory(NULL); 71 | 72 | hLib = LoadLibrary(TEXT("inpout32")); 73 | 74 | if (hLib == NULL) { 75 | fprintf(stderr,"LoadLibrary Failed.\n"); 76 | return 1; 77 | } 78 | 79 | inp32fp = (inpfuncPtr) GetProcAddress(hLib, "Inp32"); 80 | 81 | if (inp32fp == NULL) { 82 | fprintf(stderr,"GetProcAddress for Inp32 Failed.\n"); 83 | return 1; 84 | } 85 | 86 | oup32fp = (oupfuncPtr) GetProcAddress(hLib, "Out32"); 87 | 88 | if (oup32fp == NULL) { 89 | fprintf(stderr,"GetProcAddress for Oup32 Failed.\n"); 90 | return 1; 91 | } 92 | 93 | return 0; 94 | } 95 | 96 | int errcount = 0; 97 | void handlerror(int code) 98 | { 99 | if (code == 1) 100 | printf("\ntimeout waiting for ms to drop busy.\n"); 101 | else if (code == 2) 102 | printf("\ntimeout waiting for ms to ack.\n"); 103 | else if (code == 3) 104 | printf("\ntimeout waiting for ms to strobe.\n"); 105 | else if (code == 4) 106 | printf("\ntimeout waiting for ms to drop strobe.\n"); 107 | else if (code == 5) 108 | printf("\ntimeout waiting for ms to drop busy/ack.\n"); 109 | else if (code == 6) 110 | printf("\naborted waiting for ms to send.\n"); 111 | 112 | if (errcount > 20) { 113 | errcount = 0; 114 | printf("Too many errors?\n"); 115 | exit(-1); 116 | } 117 | } 118 | 119 | 120 | uint8_t recvtribble() 121 | { 122 | uint8_t trib; 123 | 124 | /* Wait for MS to raise Busy and ACK it*/ 125 | while (!(Inp32(STATUS) & BSY_IN)); 126 | Out32(DATA, 0); 127 | 128 | /* XXX: Add timeout? */ 129 | /* Wait for strobe from MS, grab tribble of data, ACK data received, 130 | * then wait for MS to ACK our ACK? */ 131 | while ((Inp32(STATUS) & STB_IN) != 0); 132 | trib = (Inp32(STATUS) >> 3) & TRIBMASK; 133 | Out32(DATA, BSY_OUT); 134 | while ((Inp32(STATUS) & STB_IN) == 0); 135 | 136 | return trib; 137 | } 138 | 139 | uint8_t recvbyte() 140 | { 141 | return (recvtribble() + (recvtribble() << 3) + ((recvtribble() & DIBMASK) << 6)); 142 | } 143 | 144 | int sendtribble(uint8_t trib) 145 | { 146 | unsigned long int timeout = 0; 147 | 148 | /* Set Busy out and wait for Busy in */ 149 | Out32(DATA, BSY_OUT); 150 | 151 | while ((Inp32(STATUS) & BSY_IN) != 0) { 152 | timeout++; 153 | if (timeout > 50000) { 154 | handlerror(1); 155 | return 0; 156 | } 157 | 158 | } 159 | 160 | /* Set data and strobe output, clear Busy out for some reason? XXX: */ 161 | Out32(DATA, ((trib & TRIBMASK) | STB_OUT)); 162 | timeout = 0; 163 | 164 | /* Wait for data acknowledge */ 165 | while ((Inp32(STATUS) & BSY_IN) == 0) { 166 | timeout++; 167 | if (timeout > 50000) { 168 | handlerror(2); 169 | return 0; 170 | } 171 | } 172 | 173 | /* Set Busy out again? */ 174 | //Out32(DATA, 0); 175 | Out32(DATA, BSY_OUT); 176 | 177 | return 1; 178 | } 179 | 180 | int sendbyte(uint8_t dat) 181 | { 182 | if (!sendtribble(dat & TRIBMASK)) return 0; 183 | 184 | dat >>= 3; 185 | if (!sendtribble(dat & TRIBMASK)) return 0; 186 | 187 | dat >>= 3; 188 | if (!sendtribble(dat & TRIBMASK)) return 0; 189 | 190 | return 1; 191 | } 192 | 193 | 194 | void usage(char **argv) 195 | { 196 | fprintf(stderr, 197 | "Usage:\n" 198 | " %s OPERATION [OPTION] ...\n" 199 | "Send or recieve data from the Mailstation Loader Utility\n\n" 200 | "OPERATION is one of:\n" 201 | " -s, --send Send file to Mailstation via parallel port\n" 202 | " -r, --revc Receive file from Mailstation via parallel port\n\n" 203 | "OPTIONS are:\n" 204 | " -h, --help This help\n" 205 | " -p, --port=ADDR LPT port address [default 0x378]\n" 206 | " -f, --file=FILE Filename to send\n" 207 | " -l, --len=LEN Length of file to recv [default 0x100000]\n", 208 | argv[0]); 209 | } 210 | 211 | 212 | int main(int argc, char **argv) 213 | { 214 | int c, i; 215 | uint16_t port = 0x0378; 216 | FILE *fd = NULL; 217 | uint8_t *fbuf = NULL; 218 | char *fpath = NULL; 219 | unsigned int filesize = 0x100000; // 1 MiB 220 | int bytecnt; 221 | enum operation opt_operation = OP_NONE; 222 | 223 | static struct option long_options[] = { 224 | { "send", no_argument, NULL, 's' }, 225 | { "recv", no_argument, NULL, 'r' }, 226 | { "port", required_argument, NULL, 'p' }, 227 | { "file", required_argument, NULL, 'f' }, 228 | { "help", no_argument, NULL, 'h' }, 229 | { "len", required_argument, NULL, 'l' }, 230 | { NULL, no_argument, NULL, 0 } 231 | }; 232 | 233 | if (argc == 1) { 234 | usage(argv); 235 | return 1; 236 | } 237 | 238 | while ((c = getopt_long(argc, argv, 239 | "srp:f:l:h", 240 | long_options, NULL)) != -1) { 241 | switch (c) { 242 | case 's': /* Send data */ 243 | opt_operation = OP_SEND; 244 | break; 245 | case 'r': /* Recv data */ 246 | opt_operation = OP_RECV; 247 | break; 248 | case 'p': /* Set port */ 249 | port = (uint16_t)strtoul(optarg, NULL, 0); 250 | break; 251 | case 'f': /* File to send/recv */ 252 | /* XXX: I know nothing of the intracacies of MAX_PATH 253 | * in Windows. This might be unsafe. You've been 254 | * warned! */ 255 | 256 | /* strlen does not include trailing \0 in its count */ 257 | fpath = (char *)malloc((size_t)strlen(optarg) + 1); 258 | strcpy(fpath, optarg); 259 | break; 260 | case 'l': /* Length of file to recv */ 261 | filesize = strtoul(optarg, NULL, 0); 262 | break; 263 | default: 264 | usage(argv); 265 | break; 266 | } 267 | } 268 | 269 | DATA = port + 0; 270 | STATUS = port + 1; 271 | CONTROL = port + 2; 272 | 273 | if (InitIOLibrary()) { 274 | fprintf(stderr, "Failed to initialize port I/O library\n"); 275 | return 1; 276 | } 277 | 278 | /* Clear the data output of the parallel port pins */ 279 | /* XXX: Do we need to clear CTRL too? */ 280 | Out32(DATA,0); 281 | 282 | /* At least one operation must be specified */ 283 | if (opt_operation == OP_NONE) { 284 | fprintf(stderr, "A send or recv operation must be specified!\n\n"); 285 | usage(argv); 286 | return 1; 287 | } 288 | 289 | /* File must be passed */ 290 | if (fpath == NULL) { 291 | fprintf(stderr, "Both send and recv require a file argument!\n\n"); 292 | usage(argv); 293 | return 1; 294 | } 295 | 296 | if (opt_operation == OP_SEND) { 297 | fd = fopen(fpath, "rb"); 298 | if (fd == NULL) { 299 | fprintf(stderr, "Error opening file: \'%s\'\n", fpath); 300 | free(fpath); 301 | return 1; 302 | } 303 | free(fpath); 304 | 305 | /* Get filesize, allocate buffer, fill buffer, close file */ 306 | fseek(fd, 0, SEEK_END); 307 | filesize = ftell(fd); 308 | fseek(fd, 0, SEEK_SET); 309 | fbuf = (uint8_t *)malloc(filesize); 310 | /* XXX: No checking of malloc return! */ 311 | fread(fbuf, 1, filesize, fd); 312 | fclose(fd); 313 | 314 | fprintf(stderr, "%d bytes loaded.\nPrepare Mailstation for transfer, and press enter to continue\n", filesize); 315 | getchar(); 316 | 317 | /* Send length of file information to MS, LSB first */ 318 | if (!sendbyte(filesize & 0xFF)) { 319 | fprintf(stderr, "FAIL SEND LOWBYTE"); 320 | return 1; 321 | } 322 | if (!sendbyte((filesize >> 8) & 0xFF)) { 323 | fprintf(stderr, "FAIL SEND HIGHBYTE"); 324 | return 1; 325 | } 326 | 327 | for (i = 0; i < filesize; i++) 328 | { 329 | if (!sendbyte(fbuf[i])) { 330 | printf("FAIL SEND @ byte %d\n", i+1); 331 | return 1; 332 | } 333 | printf("\rSent: %d/%d", (i + 1), filesize); 334 | 335 | } 336 | printf("\n"); 337 | } 338 | if (opt_operation == OP_RECV) { 339 | fprintf(stderr, "Waiting for %d bytes, writing to \'%s\'\n", 340 | filesize, fpath); 341 | /* Open file for writing */ 342 | fd = fopen(fpath, "wb"); 343 | if (fd == NULL) { 344 | fprintf(stderr, "Error opening file: \'%s\'\n", fpath); 345 | free(fpath); 346 | return 1; 347 | } 348 | free(fpath); 349 | 350 | fbuf = (uint8_t *)malloc(filesize); 351 | 352 | /* XXX: At some point, implement the following */ 353 | /* Wait for first byte, then collect bytes until they stop. This 354 | * is a bit of a hack because 2 bytes is not enough to express 355 | * the size of DF or CF for dumping. This is a weird situation 356 | * thats going to exist for now. Need to design a sane header 357 | * that can go both directions but still be compatible with the 358 | * stage 0 loader. */ 359 | bytecnt = 0; 360 | while (bytecnt < (filesize)) { 361 | fbuf[bytecnt] = recvtribble(); 362 | fbuf[bytecnt] |= ((recvtribble() & TRIBMASK) << 3); 363 | fbuf[bytecnt] |= ((recvtribble() & DIBMASK) << 6); 364 | bytecnt++; 365 | fprintf(stderr, "\rReceived: %d bytes", bytecnt); 366 | } 367 | 368 | bytecnt = 0; 369 | while (bytecnt < (filesize)) { 370 | fputc(fbuf[bytecnt], fd); 371 | bytecnt++; 372 | } 373 | fclose(fd); 374 | fprintf(stderr, "\n"); 375 | } 376 | 377 | 378 | return 0; 379 | 380 | } 381 | 382 | -------------------------------------------------------------------------------- /src/demos/FyOS/v0.01/cgafont.inc: -------------------------------------------------------------------------------- 1 | 2 | .db #0x00, #0x7e, #0x7e, #0x36, #0x08, #0x1c, #0x08, #0x00 3 | .db #0xff, #0x00, #0xff, #0xf0, #0x3c, #0xfc, #0xfe, #0x18 4 | .db #0x01, #0x40, #0x18, #0x66, #0xfe, #0x7c, #0x00, #0x18 5 | .db #0x18, #0x18, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 6 | .db #0x00, #0x0c, #0x36, #0x36, #0x0c, #0x00, #0x1c, #0x06 7 | .db #0x18, #0x06, #0x00, #0x00, #0x00, #0x00, #0x00, #0x60 8 | .db #0x3e, #0x0c, #0x1e, #0x1e, #0x38, #0x3f, #0x1c, #0x3f 9 | .db #0x1e, #0x1e, #0x00, #0x00, #0x18, #0x00, #0x06, #0x1e 10 | .db #0x3e, #0x0c, #0x3f, #0x3c, #0x1f, #0x7f, #0x7f, #0x3c 11 | .db #0x33, #0x1e, #0x78, #0x67, #0x0f, #0x63, #0x63, #0x1c 12 | .db #0x3f, #0x1e, #0x3f, #0x1e, #0x3f, #0x33, #0x33, #0x63 13 | .db #0x63, #0x33, #0x7f, #0x1e, #0x03, #0x1e, #0x08, #0x00 14 | .db #0x0c, #0x00, #0x07, #0x00, #0x38, #0x00, #0x1c, #0x00 15 | .db #0x07, #0x0c, #0x30, #0x07, #0x0e, #0x00, #0x00, #0x00 16 | .db #0x00, #0x00, #0x00, #0x00, #0x08, #0x00, #0x00, #0x00 17 | .db #0x00, #0x00, #0x00, #0x38, #0x18, #0x07, #0x6e, #0x00 18 | .db #0x1e, #0x00, #0x38, #0x7e, #0x33, #0x07, #0x0c, #0x00 19 | .db #0x7e, #0x33, #0x07, #0x33, #0x3e, #0x07, #0x63, #0x0c 20 | .db #0x38, #0x00, #0x7c, #0x1e, #0x00, #0x00, #0x1e, #0x00 21 | .db #0x00, #0xc3, #0x33, #0x18, #0x1c, #0x33, #0x1f, #0x70 22 | .db #0x38, #0x1c, #0x00, #0x00, #0x00, #0x3f, #0x3c, #0x1c 23 | .db #0x0c, #0x00, #0x00, #0xc3, #0xc3, #0x18, #0x00, #0x00 24 | .db #0x44, #0xaa, #0xdb, #0x18, #0x18, #0x18, #0x6c, #0x00 25 | .db #0x00, #0x6c, #0x6c, #0x00, #0x6c, #0x6c, #0x18, #0x00 26 | .db #0x18, #0x18, #0x00, #0x18, #0x00, #0x18, #0x18, #0x6c 27 | .db #0x6c, #0x00, #0x6c, #0x00, #0x6c, #0x00, #0x6c, #0x18 28 | .db #0x6c, #0x00, #0x00, #0x6c, #0x18, #0x00, #0x00, #0x6c 29 | .db #0x18, #0x18, #0x00, #0xff, #0x00, #0x0f, #0xf0, #0xff 30 | .db #0x00, #0x00, #0x00, #0x00, #0x3f, #0x00, #0x00, #0x00 31 | .db #0x3f, #0x1c, #0x1c, #0x38, #0x00, #0x60, #0x1c, #0x1e 32 | .db #0x00, #0x0c, #0x06, #0x18, #0x70, #0x18, #0x0c, #0x00 33 | .db #0x1c, #0x00, #0x00, #0xf0, #0x1e, #0x0e, #0x00, #0x00 34 | 35 | 36 | .db #0x00, #0x81, #0xff, #0x7f, #0x1c, #0x3e, #0x08, #0x00 37 | .db #0xff, #0x3c, #0xc3, #0xe0, #0x66, #0xcc, #0xc6, #0xdb 38 | .db #0x07, #0x70, #0x3c, #0x66, #0xdb, #0xc6, #0x00, #0x3c 39 | .db #0x3c, #0x18, #0x18, #0x0c, #0x00, #0x24, #0x18, #0xff 40 | .db #0x00, #0x1e, #0x36, #0x36, #0x3e, #0x63, #0x36, #0x06 41 | .db #0x0c, #0x0c, #0x66, #0x0c, #0x00, #0x00, #0x00, #0x30 42 | .db #0x63, #0x0e, #0x33, #0x33, #0x3c, #0x03, #0x06, #0x33 43 | .db #0x33, #0x33, #0x0c, #0x0c, #0x0c, #0x00, #0x0c, #0x33 44 | .db #0x63, #0x1e, #0x66, #0x66, #0x36, #0x46, #0x46, #0x66 45 | .db #0x33, #0x0c, #0x30, #0x66, #0x06, #0x77, #0x67, #0x36 46 | .db #0x66, #0x33, #0x66, #0x33, #0x2d, #0x33, #0x33, #0x63 47 | .db #0x63, #0x33, #0x63, #0x06, #0x06, #0x18, #0x1c, #0x00 48 | .db #0x0c, #0x00, #0x06, #0x00, #0x30, #0x00, #0x36, #0x00 49 | .db #0x06, #0x00, #0x00, #0x06, #0x0c, #0x00, #0x00, #0x00 50 | .db #0x00, #0x00, #0x00, #0x00, #0x0c, #0x00, #0x00, #0x00 51 | .db #0x00, #0x00, #0x00, #0x0c, #0x18, #0x0c, #0x3b, #0x08 52 | .db #0x33, #0x33, #0x00, #0xc3, #0x00, #0x00, #0x0c, #0x00 53 | .db #0xc3, #0x00, #0x00, #0x00, #0x63, #0x00, #0x1c, #0x0c 54 | .db #0x00, #0x00, #0x36, #0x33, #0x33, #0x07, #0x33, #0x07 55 | .db #0x33, #0x18, #0x00, #0x18, #0x36, #0x33, #0x33, #0xd8 56 | .db #0x00, #0x00, #0x38, #0x38, #0x1f, #0x00, #0x36, #0x36 57 | .db #0x00, #0x00, #0x00, #0x63, #0x63, #0x18, #0xcc, #0x33 58 | .db #0x11, #0x55, #0xee, #0x18, #0x18, #0x18, #0x6c, #0x00 59 | .db #0x00, #0x6c, #0x6c, #0x00, #0x6c, #0x6c, #0x18, #0x00 60 | .db #0x18, #0x18, #0x00, #0x18, #0x00, #0x18, #0x18, #0x6c 61 | .db #0x6c, #0x00, #0x6c, #0x00, #0x6c, #0x00, #0x6c, #0x18 62 | .db #0x6c, #0x00, #0x00, #0x6c, #0x18, #0x00, #0x00, #0x6c 63 | .db #0x18, #0x18, #0x00, #0xff, #0x00, #0x0f, #0xf0, #0xff 64 | .db #0x00, #0x1e, #0x3f, #0x7f, #0x33, #0x00, #0x66, #0x6e 65 | .db #0x0c, #0x36, #0x36, #0x0c, #0x00, #0x30, #0x06, #0x33 66 | .db #0x3f, #0x0c, #0x0c, #0x0c, #0xd8, #0x18, #0x0c, #0x6e 67 | .db #0x36, #0x00, #0x00, #0x30, #0x36, #0x18, #0x00, #0x00 68 | 69 | .db #0x00, #0xa5, #0xdb, #0x7f, #0x3e, #0x1c, #0x1c, #0x18 70 | .db #0xe7, #0x66, #0x99, #0xf0, #0x66, #0xfc, #0xfe, #0x3c 71 | .db #0x1f, #0x7c, #0x7e, #0x66, #0xdb, #0x1c, #0x00, #0x7e 72 | .db #0x7e, #0x18, #0x30, #0x06, #0x03, #0x66, #0x3c, #0xff 73 | .db #0x00, #0x1e, #0x36, #0x7f, #0x03, #0x33, #0x1c, #0x03 74 | .db #0x06, #0x18, #0x3c, #0x0c, #0x00, #0x00, #0x00, #0x18 75 | .db #0x73, #0x0c, #0x30, #0x30, #0x36, #0x1f, #0x03, #0x30 76 | .db #0x33, #0x33, #0x0c, #0x0c, #0x06, #0x3f, #0x18, #0x30 77 | .db #0x7b, #0x33, #0x66, #0x03, #0x66, #0x16, #0x16, #0x03 78 | .db #0x33, #0x0c, #0x30, #0x36, #0x06, #0x7f, #0x6f, #0x63 79 | .db #0x66, #0x33, #0x66, #0x06, #0x0c, #0x33, #0x33, #0x63 80 | .db #0x36, #0x33, #0x31, #0x06, #0x0c, #0x18, #0x36, #0x00 81 | .db #0x18, #0x1e, #0x06, #0x1e, #0x30, #0x1e, #0x06, #0x6e 82 | .db #0x36, #0x0e, #0x30, #0x66, #0x0c, #0x33, #0x1f, #0x1e 83 | .db #0x3b, #0x6e, #0x3b, #0x3e, #0x3e, #0x33, #0x33, #0x63 84 | .db #0x63, #0x33, #0x3f, #0x0c, #0x18, #0x0c, #0x00, #0x1c 85 | .db #0x03, #0x00, #0x1e, #0x3c, #0x1e, #0x1e, #0x1e, #0x1e 86 | .db #0x3c, #0x1e, #0x1e, #0x0e, #0x1c, #0x0e, #0x36, #0x00 87 | .db #0x3f, #0xfe, #0x33, #0x00, #0x00, #0x00, #0x00, #0x00 88 | .db #0x00, #0x3c, #0x33, #0x7e, #0x26, #0x1e, #0x33, #0x18 89 | .db #0x1e, #0x0e, #0x00, #0x00, #0x00, #0x33, #0x36, #0x36 90 | .db #0x0c, #0x00, #0x00, #0x33, #0x33, #0x00, #0x66, #0x66 91 | .db #0x44, #0xaa, #0xdb, #0x18, #0x18, #0x1f, #0x6c, #0x00 92 | .db #0x1f, #0x6f, #0x6c, #0x7f, #0x6f, #0x6c, #0x1f, #0x00 93 | .db #0x18, #0x18, #0x00, #0x18, #0x00, #0x18, #0xf8, #0x6c 94 | .db #0xec, #0xfc, #0xef, #0xff, #0xec, #0xff, #0xef, #0xff 95 | .db #0x6c, #0xff, #0x00, #0x6c, #0xf8, #0xf8, #0x00, #0x6c 96 | .db #0xff, #0x18, #0x00, #0xff, #0x00, #0x0f, #0xf0, #0xff 97 | .db #0x6e, #0x33, #0x33, #0x36, #0x06, #0x7e, #0x66, #0x3b 98 | .db #0x1e, #0x63, #0x63, #0x18, #0x7e, #0x7e, #0x03, #0x33 99 | .db #0x00, #0x3f, #0x18, #0x06, #0xd8, #0x18, #0x00, #0x3b 100 | .db #0x36, #0x00, #0x00, #0x30, #0x36, #0x0c, #0x3c, #0x00 101 | 102 | .db #0x00, #0x81, #0xff, #0x7f, #0x7f, #0x7f, #0x3e, #0x3c 103 | .db #0xc3, #0x42, #0xbd, #0xbe, #0x66, #0x0c, #0xc6, #0xe7 104 | .db #0x7f, #0x7f, #0x18, #0x66, #0xde, #0x36, #0x00, #0x18 105 | .db #0x18, #0x18, #0x7f, #0x7f, #0x03, #0xff, #0x7e, #0x7e 106 | .db #0x00, #0x0c, #0x00, #0x36, #0x1e, #0x18, #0x6e, #0x00 107 | .db #0x06, #0x18, #0xff, #0x3f, #0x00, #0x3f, #0x00, #0x0c 108 | .db #0x7b, #0x0c, #0x1c, #0x1c, #0x33, #0x30, #0x1f, #0x18 109 | .db #0x1e, #0x3e, #0x00, #0x00, #0x03, #0x00, #0x30, #0x18 110 | .db #0x7b, #0x33, #0x3e, #0x03, #0x66, #0x1e, #0x1e, #0x03 111 | .db #0x3f, #0x0c, #0x30, #0x1e, #0x06, #0x7f, #0x7b, #0x63 112 | .db #0x3e, #0x33, #0x3e, #0x0c, #0x0c, #0x33, #0x33, #0x6b 113 | .db #0x1c, #0x1e, #0x18, #0x06, #0x18, #0x18, #0x63, #0x00 114 | .db #0x00, #0x30, #0x3e, #0x33, #0x3e, #0x33, #0x0f, #0x33 115 | .db #0x6e, #0x0c, #0x30, #0x36, #0x0c, #0x7f, #0x33, #0x33 116 | .db #0x66, #0x33, #0x6e, #0x03, #0x0c, #0x33, #0x33, #0x6b 117 | .db #0x36, #0x33, #0x19, #0x07, #0x00, #0x38, #0x00, #0x36 118 | .db #0x33, #0x33, #0x33, #0x60, #0x30, #0x30, #0x30, #0x03 119 | .db #0x66, #0x33, #0x33, #0x0c, #0x18, #0x0c, #0x63, #0x1e 120 | .db #0x06, #0x30, #0x7f, #0x1e, #0x1e, #0x1e, #0x33, #0x33 121 | .db #0x33, #0x66, #0x33, #0x03, #0x0f, #0x3f, #0x5f, #0x3c 122 | .db #0x30, #0x0c, #0x1e, #0x33, #0x1f, #0x37, #0x7c, #0x1c 123 | .db #0x06, #0x3f, #0x3f, #0x7b, #0xdb, #0x18, #0x33, #0xcc 124 | .db #0x11, #0x55, #0x77, #0x18, #0x18, #0x18, #0x6c, #0x00 125 | .db #0x18, #0x60, #0x6c, #0x60, #0x60, #0x6c, #0x18, #0x00 126 | .db #0x18, #0x18, #0x00, #0x18, #0x00, #0x18, #0x18, #0x6c 127 | .db #0x0c, #0x0c, #0x00, #0x00, #0x0c, #0x00, #0x00, #0x00 128 | .db #0x6c, #0x00, #0x00, #0x6c, #0x18, #0x18, #0x00, #0x6c 129 | .db #0x18, #0x18, #0x00, #0xff, #0x00, #0x0f, #0xf0, #0xff 130 | .db #0x3b, #0x1f, #0x03, #0x36, #0x0c, #0x1b, #0x66, #0x18 131 | .db #0x33, #0x7f, #0x63, #0x3e, #0xdb, #0xdb, #0x1f, #0x33 132 | .db #0x3f, #0x0c, #0x0c, #0x0c, #0x18, #0x18, #0x3f, #0x00 133 | .db #0x1c, #0x18, #0x00, #0x30, #0x36, #0x06, #0x3c, #0x00 134 | 135 | .db #0x00, #0xbd, #0xc3, #0x3e, #0x3e, #0x7f, #0x7f, #0x3c 136 | .db #0xc3, #0x42, #0xbd, #0x33, #0x3c, #0x0c, #0xc6, #0xe7 137 | .db #0x1f, #0x7c, #0x18, #0x66, #0xd8, #0x36, #0x7e, #0x7e 138 | .db #0x18, #0x7e, #0x30, #0x06, #0x03, #0x66, #0xff, #0x3c 139 | .db #0x00, #0x0c, #0x00, #0x7f, #0x30, #0x0c, #0x3b, #0x00 140 | .db #0x06, #0x18, #0x3c, #0x0c, #0x00, #0x00, #0x00, #0x06 141 | .db #0x6f, #0x0c, #0x06, #0x30, #0x7f, #0x30, #0x33, #0x0c 142 | .db #0x33, #0x30, #0x00, #0x00, #0x06, #0x00, #0x18, #0x0c 143 | .db #0x7b, #0x3f, #0x66, #0x03, #0x66, #0x16, #0x16, #0x73 144 | .db #0x33, #0x0c, #0x33, #0x36, #0x46, #0x6b, #0x73, #0x63 145 | .db #0x06, #0x3b, #0x36, #0x18, #0x0c, #0x33, #0x33, #0x7f 146 | .db #0x1c, #0x0c, #0x4c, #0x06, #0x30, #0x18, #0x00, #0x00 147 | .db #0x00, #0x3e, #0x66, #0x03, #0x33, #0x3f, #0x06, #0x33 148 | .db #0x66, #0x0c, #0x30, #0x1e, #0x0c, #0x7f, #0x33, #0x33 149 | .db #0x66, #0x33, #0x66, #0x1e, #0x0c, #0x33, #0x33, #0x7f 150 | .db #0x1c, #0x33, #0x0c, #0x0c, #0x18, #0x0c, #0x00, #0x63 151 | .db #0x1e, #0x33, #0x3f, #0x7c, #0x3e, #0x3e, #0x3e, #0x03 152 | .db #0x7e, #0x3f, #0x3f, #0x0c, #0x18, #0x0c, #0x7f, #0x33 153 | .db #0x1e, #0xfe, #0x33, #0x33, #0x33, #0x33, #0x33, #0x33 154 | .db #0x33, #0x66, #0x33, #0x03, #0x06, #0x0c, #0x63, #0x18 155 | .db #0x3e, #0x0c, #0x33, #0x33, #0x33, #0x3f, #0x00, #0x00 156 | .db #0x03, #0x03, #0x30, #0xcc, #0xec, #0x18, #0x66, #0x66 157 | .db #0x44, #0xaa, #0xdb, #0x18, #0x1f, #0x1f, #0x6f, #0x7f 158 | .db #0x1f, #0x6f, #0x6c, #0x6f, #0x7f, #0x7f, #0x1f, #0x1f 159 | .db #0xf8, #0xff, #0xff, #0xf8, #0xff, #0xff, #0xf8, #0xec 160 | .db #0xfc, #0xec, #0xff, #0xef, #0xec, #0xff, #0xef, #0xff 161 | .db #0xff, #0xff, #0xff, #0xfc, #0xf8, #0xf8, #0xfc, #0xff 162 | .db #0xff, #0x1f, #0xf8, #0xff, #0xff, #0x0f, #0xf0, #0x00 163 | .db #0x13, #0x33, #0x03, #0x36, #0x06, #0x1b, #0x66, #0x18 164 | .db #0x33, #0x63, #0x36, #0x33, #0xdb, #0xdb, #0x03, #0x33 165 | .db #0x00, #0x0c, #0x06, #0x18, #0x18, #0x18, #0x00, #0x6e 166 | .db #0x00, #0x18, #0x18, #0x37, #0x36, #0x1e, #0x3c, #0x00 167 | 168 | .db #0x00, #0x99, #0xe7, #0x1c, #0x1c, #0x6b, #0x3e, #0x18 169 | .db #0xe7, #0x66, #0x99, #0x33, #0x18, #0x0e, #0xe6, #0x3c 170 | .db #0x07, #0x70, #0x7e, #0x00, #0xd8, #0x1c, #0x7e, #0x3c 171 | .db #0x18, #0x3c, #0x18, #0x0c, #0x7f, #0x24, #0xff, #0x18 172 | .db #0x00, #0x00, #0x00, #0x36, #0x1f, #0x66, #0x33, #0x00 173 | .db #0x0c, #0x0c, #0x66, #0x0c, #0x0c, #0x00, #0x0c, #0x03 174 | .db #0x67, #0x0c, #0x33, #0x33, #0x30, #0x33, #0x33, #0x0c 175 | .db #0x33, #0x18, #0x0c, #0x0c, #0x0c, #0x3f, #0x0c, #0x00 176 | .db #0x03, #0x33, #0x66, #0x66, #0x36, #0x46, #0x06, #0x66 177 | .db #0x33, #0x0c, #0x33, #0x66, #0x66, #0x63, #0x63, #0x36 178 | .db #0x06, #0x1e, #0x66, #0x33, #0x0c, #0x33, #0x1e, #0x77 179 | .db #0x36, #0x0c, #0x66, #0x06, #0x60, #0x18, #0x00, #0x00 180 | .db #0x00, #0x33, #0x66, #0x33, #0x33, #0x03, #0x06, #0x3e 181 | .db #0x66, #0x0c, #0x33, #0x36, #0x0c, #0x6b, #0x33, #0x33 182 | .db #0x3e, #0x3e, #0x06, #0x30, #0x2c, #0x33, #0x1e, #0x7f 183 | .db #0x36, #0x3e, #0x26, #0x0c, #0x18, #0x0c, #0x00, #0x63 184 | .db #0x18, #0x33, #0x03, #0x66, #0x33, #0x33, #0x33, #0x1e 185 | .db #0x06, #0x03, #0x03, #0x0c, #0x18, #0x0c, #0x63, #0x3f 186 | .db #0x06, #0x33, #0x33, #0x33, #0x33, #0x33, #0x33, #0x33 187 | .db #0x3e, #0x3c, #0x33, #0x7e, #0x67, #0x3f, #0xf3, #0x18 188 | .db #0x33, #0x0c, #0x33, #0x33, #0x33, #0x3b, #0x7e, #0x3e 189 | .db #0x33, #0x03, #0x30, #0x66, #0xf6, #0x18, #0xcc, #0x33 190 | .db #0x11, #0x55, #0xee, #0x18, #0x18, #0x18, #0x6c, #0x6c 191 | .db #0x18, #0x6c, #0x6c, #0x6c, #0x00, #0x00, #0x00, #0x18 192 | .db #0x00, #0x00, #0x18, #0x18, #0x00, #0x18, #0x18, #0x6c 193 | .db #0x00, #0x6c, #0x00, #0x6c, #0x6c, #0x00, #0x6c, #0x00 194 | .db #0x00, #0x18, #0x6c, #0x00, #0x00, #0x18, #0x6c, #0x6c 195 | .db #0x18, #0x00, #0x18, #0xff, #0xff, #0x0f, #0xf0, #0x00 196 | .db #0x3b, #0x1f, #0x03, #0x36, #0x33, #0x1b, #0x3e, #0x18 197 | .db #0x1e, #0x36, #0x36, #0x33, #0x7e, #0x7e, #0x06, #0x33 198 | .db #0x3f, #0x00, #0x00, #0x00, #0x18, #0x1b, #0x0c, #0x3b 199 | .db #0x00, #0x00, #0x00, #0x36, #0x00, #0x00, #0x3c, #0x00 200 | 201 | .db #0x00, #0x81, #0xff, #0x08, #0x08, #0x08, #0x08, #0x00 202 | .db #0xff, #0x3c, #0xc3, #0x33, #0x7e, #0x0f, #0x67, #0xdb 203 | .db #0x01, #0x40, #0x3c, #0x66, #0xd8, #0x33, #0x7e, #0x18 204 | .db #0x18, #0x18, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 205 | .db #0x00, #0x0c, #0x00, #0x36, #0x0c, #0x63, #0x6e, #0x00 206 | .db #0x18, #0x06, #0x00, #0x00, #0x0c, #0x00, #0x0c, #0x01 207 | .db #0x3e, #0x3f, #0x3f, #0x1e, #0x78, #0x1e, #0x1e, #0x0c 208 | .db #0x1e, #0x0e, #0x0c, #0x0c, #0x18, #0x00, #0x06, #0x0c 209 | .db #0x1e, #0x33, #0x3f, #0x3c, #0x1f, #0x7f, #0x0f, #0x7c 210 | .db #0x33, #0x1e, #0x1e, #0x67, #0x7f, #0x63, #0x63, #0x1c 211 | .db #0x0f, #0x38, #0x67, #0x1e, #0x1e, #0x3f, #0x0c, #0x63 212 | .db #0x63, #0x1e, #0x7f, #0x1e, #0x40, #0x1e, #0x00, #0x00 213 | .db #0x00, #0x6e, #0x3b, #0x1e, #0x6e, #0x1e, #0x0f, #0x30 214 | .db #0x67, #0x1e, #0x33, #0x67, #0x1e, #0x63, #0x33, #0x1e 215 | .db #0x06, #0x30, #0x0f, #0x1f, #0x18, #0x6e, #0x0c, #0x36 216 | .db #0x63, #0x30, #0x3f, #0x38, #0x18, #0x07, #0x00, #0x7f 217 | .db #0x30, #0x7e, #0x1e, #0xfc, #0x7e, #0x7e, #0x7e, #0x30 218 | .db #0x3c, #0x1e, #0x1e, #0x1e, #0x3c, #0x1e, #0x63, #0x33 219 | .db #0x3f, #0xfe, #0x73, #0x1e, #0x1e, #0x1e, #0x7e, #0x7e 220 | .db #0x30, #0x18, #0x1e, #0x18, #0x3f, #0x0c, #0x63, #0x1b 221 | .db #0x7e, #0x1e, #0x1e, #0x7e, #0x33, #0x33, #0x00, #0x00 222 | .db #0x1e, #0x00, #0x00, #0x33, #0xf3, #0x18, #0x00, #0x00 223 | .db #0x44, #0xaa, #0xdb, #0x18, #0x18, #0x18, #0x6c, #0x6c 224 | .db #0x18, #0x6c, #0x6c, #0x6c, #0x00, #0x00, #0x00, #0x18 225 | .db #0x00, #0x00, #0x18, #0x18, #0x00, #0x18, #0x18, #0x6c 226 | .db #0x00, #0x6c, #0x00, #0x6c, #0x6c, #0x00, #0x6c, #0x00 227 | .db #0x00, #0x18, #0x6c, #0x00, #0x00, #0x18, #0x6c, #0x6c 228 | .db #0x18, #0x00, #0x18, #0xff, #0xff, #0x0f, #0xf0, #0x00 229 | .db #0x6e, #0x03, #0x03, #0x36, #0x3f, #0x0e, #0x06, #0x18 230 | .db #0x0c, #0x1c, #0x77, #0x1e, #0x00, #0x06, #0x1c, #0x33 231 | .db #0x00, #0x3f, #0x3f, #0x3f, #0x18, #0x1b, #0x0c, #0x00 232 | .db #0x00, #0x00, #0x00, #0x3c, #0x00, #0x00, #0x00, #0x00 233 | 234 | .db #0x00, #0x7e, #0x7e, #0x00, #0x00, #0x1c, #0x1c, #0x00 235 | .db #0xff, #0x00, #0xff, #0x1e, #0x18, #0x07, #0x03, #0x18 236 | .db #0x00, #0x00, #0x18, #0x00, #0x00, #0x1e, #0x00, #0xff 237 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 238 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 239 | .db #0x00, #0x00, #0x00, #0x00, #0x06, #0x00, #0x00, #0x00 240 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 241 | .db #0x00, #0x00, #0x00, #0x06, #0x00, #0x00, #0x00, #0x00 242 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 243 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 244 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 245 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0xff 246 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x1f 247 | .db #0x00, #0x00, #0x1e, #0x00, #0x00, #0x00, #0x00, #0x00 248 | .db #0x0f, #0x78, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 249 | .db #0x00, #0x1f, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 250 | .db #0x1e, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x1c 251 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 252 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 253 | .db #0x1f, #0x00, #0x00, #0x18, #0x00, #0x0c, #0xe3, #0x0e 254 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 255 | .db #0x00, #0x00, #0x00, #0xf0, #0xc0, #0x00, #0x00, #0x00 256 | .db #0x11, #0x55, #0x77, #0x18, #0x18, #0x18, #0x6c, #0x6c 257 | .db #0x18, #0x6c, #0x6c, #0x6c, #0x00, #0x00, #0x00, #0x18 258 | .db #0x00, #0x00, #0x18, #0x18, #0x00, #0x18, #0x18, #0x6c 259 | .db #0x00, #0x6c, #0x00, #0x6c, #0x6c, #0x00, #0x6c, #0x00 260 | .db #0x00, #0x18, #0x6c, #0x00, #0x00, #0x18, #0x6c, #0x6c 261 | .db #0x18, #0x00, #0x18, #0xff, #0xff, #0x0f, #0xf0, #0x00 262 | .db #0x00, #0x03, #0x00, #0x00, #0x00, #0x00, #0x03, #0x00 263 | .db #0x3f, #0x00, #0x00, #0x00, #0x00, #0x03, #0x00, #0x00 264 | .db #0x00, #0x00, #0x00, #0x00, #0x18, #0x0e, #0x00, #0x00 265 | .db #0x00, #0x00, #0x00, #0x38, #0x00, #0x00, #0x00, #0x00 266 | 267 | 268 | --------------------------------------------------------------------------------