kasse
.cproject
.project
-*.s
-*.o
+build/
*.P00
itemz
*.d64
include/version.h
+include/charset_umlauts.h
tags
items
+credits
cat
+charmap
+ascii
*.lbl
CC=cc65
AS=ca65
LD=cl65
-INCLUDES:=$(wildcard include/*.h) include/version.h
+INCLUDES:=$(wildcard include/*.h) include/version.h include/charset_umlauts.h
GV:=$(shell git describe --tags --always)
CFLAGS= -I include -t c128 -g
-.PHONY: include/version.h clean dist-clean format
+.PHONY: include/version.h include/charset_umlauts.h clean dist-clean format
all: kasse itemz cat
${CC} ${CFLAGS} -O $< -o build/$(addsuffix .s,$(shell basename $< .c))
${AS} ${CFLAGS} build/$(addsuffix .s,$(shell basename $< .c)) -o $@
+build/%.o: src/%.s
+ ${AS} ${CFLAGS} $< -o $@
+
include/version.h:
mkdir -p build
echo "#define GV \"${GV}\"" > $@
-kasse: build/config.o build/kasse.o build/general.o build/credit_manager.o build/c128time.o build/print.o
+include/charset_umlauts.h:
+ ./util/mkfont assets/umlauts.pbm chars_umlauts > $@
+
+kasse: build/config.o build/kasse.o build/general.o build/credit_manager.o build/c128time.o build/print.o build/vdc_patch_charset.o build/vdc_util.o
${LD} -Ln $@.lbl -t c128 $^ -o $@
itemz: build/config.o build/itemz.o build/general.o build/credit_manager.o build/c128time.o build/print.o
cat: build/general.o build/cat.o
${LD} -Ln $@.lbl -t c128 $^ -o $@
+charmap: build/print_charmap.o build/vdc_util.o build/vdc_patch_charset.o
+ ${LD} -Ln $@.lbl -t c128 $^ -o $@
+
+ascii: build/print_ascii.o
+ ${LD} -Ln $@.lbl -t c128 $^ -o $@
+
package: all
c1541 -format "${GV}",KA d64 kasse.d64
c1541 -attach kasse.d64 -write kasse
--- /dev/null
+#ifndef __VDC_PATCH_CHARSET_H_
+#define __VDC_PATCH_CHARSET_H_
+
+void vdc_patch_charset(void);
+
+#define EURSYM "\xA2"
+#define AUML "\x9C"
+#define OUML "\x9E"
+#define UUML "\x9F"
+#define aUML "\xA6"
+#define oUML "\xA8"
+#define uUML "\xA9"
+#define szLIG "\xBF"
+
+#endif // __VDC_PATCH_CHARSET_H_
--- /dev/null
+#ifndef __VDC_UTIL_H_
+#define __VDC_UTIL_H_
+
+extern void __fastcall__ vdc_load_thinfont(void);
+extern unsigned char __fastcall__ vdc_read_reg(unsigned char reg);
+extern unsigned __fastcall__ vdc_read_addr(unsigned char reg);
+extern void __fastcall__ vdc_write_reg(unsigned char reg, unsigned char data);
+extern void __fastcall__ vdc_write_addr(unsigned char reg, unsigned addr);
+extern void __fastcall__ vdc_read_mem(unsigned dest, unsigned src, unsigned n);
+extern void __fastcall__ vdc_write_mem(unsigned dest, const void *src,
+ unsigned n);
+extern void __fastcall__ vdc_load_thinfont(void);
+
+#endif // __VDC_UTIL_H_
#include <conio.h>
#include "general.h"
+#include "vdc_patch_charset.h"
/*
* get_input_terminated_by() reads input (handling backspace correctly) until
}
char *format_euro(char *s, int maxlen, int cent) {
- if (snprintf(s, maxlen, "%3d,%02dEUR", cent / 100, cent % 100) > maxlen)
+ if (snprintf(s, maxlen, "%3d,%02d" EURSYM, cent / 100, cent % 100) > maxlen)
return NULL;
return s;
}
#include <string.h>
#include <cbm.h>
#include <c128.h>
+#include <6502.h>
#include "general.h"
#include "config.h"
#include "c128time.h"
#include "print.h"
#include "version.h"
+#include "vdc_patch_charset.h"
// drucker 4 oder 5
// graphic 4,0,10
textcolor(TC_YELLOW);
cprintf("%2d", i);
textcolor(TC_LIGHT_GRAY);
- cprintf(": %-" xstr(MAX_ITEM_NAME_LENGTH) "s \xDD%s, %3dx ",
+ cprintf(": %-" xstr(MAX_ITEM_NAME_LENGTH) "s \xDD%s, %3dx ",
status.status[i].item_name, profit, status.status[i].times_sold);
}
exit(1);
}
textcolor(TC_CYAN);
- cprintf("C128-Kassenprogramm (phil_fry, sECuRE, sur5r) " GV "\r\n");
+ cprintf("C128-Kassenprogramm (phil_fry, sECuRE, sur5r, mxf) " GV "\r\n");
textcolor(TC_LIGHT_GRAY);
cprintf("\r\nUhrzeit: %s (wird nicht aktualisiert)\r\n"
"Eingenommen: %s, Verkauft: %ld Dinge, Drucken: %s\r\n",
continue;
}
if (c == 27) {
- cprintf("Kauf abgebrochen, druecke RETURN...\r\n");
+ cprintf("Kauf abgebrochen, dr" uUML "cke RETURN...\r\n");
get_input();
return 1;
}
einheiten = atoi(entered) * negative;
if (einheiten > 100 || einheiten < -100 || einheiten == 0) {
- cprintf("\r\nEinheit nicht in [-100, 100] oder 0, Abbruch, druecke "
+ cprintf("\r\nEinheit nicht in [-100, 100] oder 0, Abbruch, dr" uUML "cke "
"RETURN...\r\n");
cgetc();
return 1;
}
textcolor(TC_LIGHT_GREEN);
- cprintf("\r\nVerbleibendes Guthaben fuer %s: %s. Druecke RETURN...\r\n",
+ cprintf("\r\nVerbleibendes Guthaben f" uUML "r %s: %s. Dr" uUML
+ "cke RETURN...\r\n",
nickname, rest);
textcolor(TC_LIGHT_GRAY);
get_input();
} else {
textcolor(TC_LIGHT_RED);
cprintf("\r\nNickname nicht gefunden in der Guthabenverwaltung! Abbruch, "
- "druecke RETURN...\r\n");
+ "dr" uUML "cke RETURN...\r\n");
textcolor(TC_LIGHT_GRAY);
get_input();
return 0;
break;
cputc(c);
if (c == 27) {
- cprintf("Kauf abgebrochen, druecke RETURN...\r\n");
+ cprintf("Kauf abgebrochen, dr" uUML "cke RETURN...\r\n");
get_input();
return;
} else if (c == '-' && i == 0)
/* clock CPU at double the speed (a whopping 2 Mhz!) */
fast();
+ SEI();
+ vdc_patch_charset();
+ CLI();
+
clrscr();
/* Allocate logging buffer memory */
} else if (*c == 'f') {
buy_custom();
} else if (*c == 's') {
+ cprintf("\r\nsaving items.. ");
save_items();
+ cprintf("ok\r\nsaving credits.. ");
save_credits();
+ cprintf("ok\r\nflushing log.. ");
log_flush();
- cprintf("\r\nStatefile/Creditfile/Log gesichert, druecke RETURN...\r\n");
+ cprintf("ok\r\nStatefile/Creditfile/Log gesichert, dr" uUML
+ "cke RETURN...\r\n");
get_input();
} else if (*c == 'g') {
credit_manager();
--- /dev/null
+#include <stdlib.h>
+#include <conio.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <c128.h>
+
+//#include "vdc_patch_charset.h"
+
+int main(void) {
+ int i = 80;
+ unsigned char c[3] = {0x20, 0x20, 0};
+ unsigned char pos[5];
+
+ videomode(0x80);
+ fast();
+ clrscr();
+
+ cputsxy(4, 0, "0 1 2 3 4 5 6 7 8 9 A B C D E F");
+ cputs("\r\n");
+
+ /* unrolled, so compiler can do its magick */
+ cputs("20 \x20 \x21 \x22 \x23 \x24 \x25 \x26 \x27 \x28 \x29 \x2a \x2b \x2c "
+ "\x2d \x2e \x2f \r\n");
+ cputs("30 \x30 \x31 \x32 \x33 \x34 \x35 \x36 \x37 \x38 \x39 \x3a \x3b \x3c "
+ "\x3d \x3e \x3f \r\n");
+ cputs("40 \x40 \x41 \x42 \x43 \x44 \x45 \x46 \x47 \x48 \x49 \x4a \x4b \x4c "
+ "\x4d \x4e \x4f \r\n");
+ cputs("50 \x50 \x51 \x52 \x53 \x54 \x55 \x56 \x57 \x58 \x59 \x5a \x5b \x5c "
+ "\x5d \x5e \x5f \r\n");
+ cputs("60 \x60 \x61 \x62 \x63 \x64 \x65 \x66 \x67 \x68 \x69 \x6a \x6b \x6c "
+ "\x6d \x6e \x6f \r\n");
+ cputs("70 \x70 \x71 \x72 \x73 \x74 \x75 \x76 \x77 \x78 \x79 \x7a \x7b \x7c "
+ "\x7d \x7e \x7f \r\n");
+ cputs("80 \x80 \x81 \x82 \x83 \x84 \x85 \x86 \x87 \x88 \x89 \x8a \x8b \x8c "
+ "\x8d \x8e \x8f \r\n");
+ cputs("90 \x90 \x91 \x92 \x93 \x94 \x95 \x96 \x97 \x98 \x99 \x9a \x9b \x9c "
+ "\x9d \x9e \x9f \r\n");
+ cputs("a0 \xa0 \xa1 \xa2 \xa3 \xa4 \xa5 \xa6 \xa7 \xa8 \xa9 \xaa \xab \xac "
+ "\xad \xae \xaf \r\n");
+ cputs("b0 \xb0 \xb1 \xb2 \xb3 \xb4 \xb5 \xb6 \xb7 \xb8 \xb9 \xba \xbb \xbc "
+ "\xbd \xbe \xbf \r\n");
+ cputs("c0 \xc0 \xc1 \xc2 \xc3 \xc4 \xc5 \xc6 \xc7 \xc8 \xc9 \xca \xcb \xcc "
+ "\xcd \xce \xcf \r\n");
+ cputs("d0 \xd0 \xd1 \xd2 \xd3 \xd4 \xd5 \xd6 \xd7 \xd8 \xd9 \xda \xdb \xdc "
+ "\xdd \xde \xdf \r\n");
+ cputs("e0 \xe0 \xe1 \xe2 \xe3 \xe4 \xe5 \xe6 \xe7 \xe8 \xe9 \xea \xeb \xec "
+ "\xed \xee \xef \r\n");
+ cputs("f0 \xf0 \xf1 \xf2 \xf3 \xf4 \xf5 \xf6 \xf7 \xf8 \xf9 \xfa \xfb \xfc "
+ "\xfd \xfe \xff \r\n");
+
+ // cputs(EURSYM aUML oUML uUML AUML OUML UUML szLIG "\r\n");
+ return 0;
+}
--- /dev/null
+#include <stdlib.h>
+#include <conio.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdbool.h>
+
+#include <c128.h>
+#include <6502.h>
+
+#include "vdc_util.h"
+#include "vdc_patch_charset.h"
+
+int main(void) {
+ int i = 80;
+ unsigned char c[2] = {0x00, 0x20};
+ unsigned char pos[5];
+
+ /* char attribute, alternate char set, white, full intensity.
+ * set to 0x0f for normal char set
+ */
+ unsigned char blank = 0x8f;
+
+ videomode(0x80);
+ fast();
+ clrscr();
+
+ cputsxy(4, 0, "0 1 2 3 4 5 6 7 8 9 A B C D E F");
+
+ /* Manipulate the VDC with IRQs turned off.
+ * KERNALs default IRQ handler will also try to read the VDC status
+ * register, which could interfere with our code trying to read it.
+ */
+ SEI();
+
+ // vdc_load_thinfont();
+ vdc_patch_charset();
+
+ /* write 16 chars per line */
+ do {
+ if ((*c % 16) == 0) {
+ sprintf(pos, "%02x ", *c);
+ vdc_write_mem(i, pos, 4);
+ i = i + 4;
+ }
+
+ vdc_write_mem(i, c, 2);
+ ++(*c);
+ i = i + 2;
+
+ if ((*c % 16) == 0) {
+ i = i + 44;
+ }
+ } while (*c);
+
+ /* clear attribute mem */
+ i = 0;
+ while (++i <= 2000)
+ vdc_write_mem(i + 0x800, &blank, 1);
+
+ CLI();
+
+ /* set cursor, so basic's prompt won't overwrite our output */
+ gotoxy(0, 18);
+ cputs(EURSYM aUML oUML uUML AUML OUML UUML szLIG);
+ return 0;
+}
--- /dev/null
+#include <string.h>
+
+#include "charset_umlauts.h"
+#include "vdc_util.h"
+
+void vdc_patch_charset(void) {
+ int i = 0;
+ /* start of the shifted charset */
+ const unsigned int base_addr = 0x3000;
+ /* EUR Ä Ö Ü ä ö ü ß */
+ unsigned char map[8] = {0x62, 0x5C, 0x5E, 0x5F, 0x66, 0x68, 0x69, 0x7F};
+ unsigned char *p = map;
+
+ for (; i < sizeof(chars_umlauts); i += 8) {
+ vdc_write_mem(base_addr + *p * 16, chars_umlauts + i, 8);
+ ++p;
+ }
+}
--- /dev/null
+;;; -*- tab-width: 8; -*-
+ .export _vdc_read_reg, _vdc_read_addr, _vdc_read_mem
+ .export _vdc_write_reg, _vdc_write_addr, _vdc_write_mem
+ .export _vdc_load_thinfont
+ .import popa, popax
+ .importzp ptr1, ptr2
+ .include "c128.inc"
+ .debuginfo on
+
+;;; useful documentation:
+;;; - 6502 instruction/addressing mode overview
+;;; - http://www.obelisk.me.uk/6502/index.html
+;;; - cc65 assembler interfacing with C
+;;; - https://github.com/cc65/wiki/wiki/Parameter-passing-and-calling-conventions
+;;; - https://github.com/cc65/wiki/wiki/Parameter-and-return-stacks
+;;; - https://github.com/cc65/wiki/wiki/Using-runtime-zeropage-locations-in-assembly-language
+;;; - Programming the VDC
+;;; - Chapter 10 of http: //www.pagetable.com/docs/Commodore%20128%20Programmer%27s%20Reference%20Guide.pdf
+
+VDC_ADDR_REG := 19
+VDC_MEM_REG := 31
+
+;;; unsigned char __fastcall__ vdc_read_reg (unsigned char reg);
+_vdc_read_reg:
+ ldx #0 ; clear high byte
+vdc_read_reg:
+ sta VDC_INDEX
+
+@wait: bit VDC_INDEX ; busy wait until vdc is ready
+ bpl @wait
+
+ lda VDC_DATA
+ rts
+
+;;; unsigned __fastcall__ vdc_read_addr (unsigned char reg);
+_vdc_read_addr:
+ tay ; save copy of vdc reg
+ jsr vdc_read_reg
+ tax ; save high byte
+ dey ; set low byte vdc reg
+ tya
+ jsr vdc_read_reg
+ rts
+
+;;; void __fastcall__ vdc_write_reg (unsigned char reg, unsigned char data);
+_vdc_write_reg:
+ pha
+ jsr popa
+ tay
+ pla
+vdc_write_reg:
+ sty VDC_INDEX
+
+@wait: bit VDC_INDEX ; busy wait until vdc is ready
+ bpl @wait
+
+ sta VDC_DATA
+ rts
+
+;;; void __fastcall__ vdc_write_addr (unsigned char reg, unsigned addr);
+_vdc_write_addr:
+ pha
+ jsr popa
+ tay
+ pla
+vdc_write_addr:
+ jsr vdc_write_reg
+ txa ; get high byte of addr
+ dey
+ jsr vdc_write_reg
+ rts
+
+;;; void __fastcall__ vdc_read_mem (unsigned dest, unsigned src, unsigned n);
+_vdc_read_mem:
+ sta ptr1 ; store n
+ stx ptr1+1
+
+ jsr popax
+ ldy #VDC_ADDR_REG
+ jsr vdc_write_addr
+
+ jsr popax
+ sta ptr2
+ stx ptr2+1
+
+ lda #VDC_MEM_REG
+ sta VDC_INDEX
+
+ ldy #0 ; offset into dest
+
+ ;; first, loop over the high byte of n, 256 times
+ ldx ptr1+1 ; get high byte of n
+ beq @low ; skip if zero
+
+@cpyhi: bit VDC_INDEX
+ bpl @cpyhi
+
+ lda VDC_DATA
+ sta (ptr2),y
+ iny
+ bne @cpyhi ; have we copied 256 bytes yet?
+
+ inc ptr2+1 ; adjust dest pointer
+ dex
+ bne @cpyhi ; read 256 more bytes
+
+@low: ldx ptr1 ; get low byte of n
+ beq @done ; skip if zero
+
+@cpy: bit VDC_INDEX
+ bpl @cpy
+
+ lda VDC_DATA
+ sta (ptr2),y
+ iny
+ dex
+ bne @cpy
+
+@done: rts
+
+;;; void __fastcall__ vdc_write_mem (unsigned dest, const void* src, unsigned n);
+_vdc_write_mem:
+ sta ptr1 ; store n
+ stx ptr1+1
+
+ jsr popax
+ sta ptr2
+ stx ptr2+1
+
+ jsr popax
+ ldy #VDC_ADDR_REG
+ jsr vdc_write_addr
+
+ lda #VDC_MEM_REG
+ sta VDC_INDEX
+
+ ldy #0 ; offset into dest
+
+ ;; first, loop over the high byte of n
+ ldx ptr1+1 ; get high byte of n
+ beq @low ; skip if zero
+
+@cpyhi: bit VDC_INDEX
+ bpl @cpyhi
+
+ lda (ptr2),y
+ sta VDC_DATA
+ iny
+ bne @cpyhi ; have we copied 256 bytes yet?
+
+ inc ptr2+1 ; adjust dest pointer
+ dex
+ bne @cpyhi ; read 256 more bytes
+
+@low: ldx ptr1 ; get low byte of n
+ beq @done ; skip if zero
+
+@cpy: bit VDC_INDEX
+ bpl @cpy
+
+ lda (ptr2),y
+ sta VDC_DATA
+ iny
+ dex
+ bne @cpy
+
+@done: rts
+
+;;; void __fastcall__ vdc_load_thinfont (void);
+_vdc_load_thinfont:
+ ;; save MMU register
+ lda $0
+ pha
+ lda $1
+ pha
+
+ ;; map in alternate font
+ lda #$FF
+ sta $0
+ lda #$33
+ sta $1
+
+ ;; call kernal load font routine
+ jsr $FF62
+
+ ;; restore MMU
+ pla
+ sta $1
+ pla
+ sta $0
+ rts
--- /dev/null
+#!/usr/bin/env perl
+use strict;
+use warnings;
+use v5.10;
+
+my ($fname, $array_name) = @ARGV;
+
+die "Usage: $0 <file>\n" unless $fname;
+
+my $fh;
+open $fh, '<', $fname or die "$0: $!\n";
+
+my $header = <$fh>;
+die "$0: $fname: unknown file format\n" unless $header eq "P4\n";
+
+my $len;
+{
+ my $line = <$fh>;
+ chomp $line;
+ last if ($len) = $line =~ /^8 (\d+)$/;
+ redo if $line =~ /^#/;
+ die "$0: $fname: couldn't parse header\n";
+}
+
+local $/;
+# read rest of file and return a list of the ascii value for each byte
+my @bin = map { ord($_) } split //, <$fh>;
+
+die "$0: $fname should have $len bytes image data, got: " . scalar(@bin) . "\n"
+ unless scalar(@bin) == $len;
+
+say "/* autogenerated by util/mkfont */";
+say "const unsigned char $array_name\[$len] = {";
+
+# break up in max. 8 bytes per line
+while (my @line = splice @bin, 0, 8) {
+ # seperated by commata, depending on how many bytes we have
+ my $hexify = join ', ', ('0x%02x') x scalar(@line);
+ printf " $hexify" , @line;
+ # if there's more bytes left, seperate next block by a comma
+ print scalar(@bin) > 0 ? ",\n" : "\n";
+}
+
+say "};"