diff --git a/12hourclk.c b/12hourclk.c new file mode 100644 index 0000000..f8e9ee9 --- /dev/null +++ b/12hourclk.c @@ -0,0 +1,104 @@ +#include /* printf, scanf */ +#include /* toupper */ +#include "12hourclk.h" + +static char *meridiem_text(meridiem_t m) +{ + if (m == ANTE_MERIDIEM) { + return "am"; + } + else { + return "pm"; + } +} + +void read_interactively(twleve_hour_clock_t *clock) +{ + char meridiem_input[3]; + + printf("Hour:"); + scanf("%2ui", &(clock->hours)); + printf("Minute:"); + scanf("%2ui", &(clock->minutes)); + printf("AM or PM:"); + scanf("%2s", meridiem_input); + clock->seconds = 0; + if (toupper(meridiem_input[0]) == 'A') { + clock->meridiem = ANTE_MERIDIEM; + } + else { + clock->meridiem = POST_MERIDIEM; + } +} + +void add_one_second(twleve_hour_clock_t *clock) +{ + if (clock->seconds < 59) { + ++(clock->seconds); + } + else { + clock->seconds = 0; + if (clock->minutes < 59) { + ++(clock->minutes); + } + else { + clock->minutes = 0; + if (clock->hours < 11) { + ++(clock->hours); + } + else if (clock->hours == 11) { + ++(clock->hours); + if (clock->meridiem == ANTE_MERIDIEM) { + clock->meridiem = POST_MERIDIEM; + } + else { + clock->meridiem = ANTE_MERIDIEM; + } + } + else { + clock->hours = 1; + } + } + } +} + +void add_seconds(twleve_hour_clock_t *clock, uint8_t seconds) +{ + uint16_t sum; + uint16_t minutes_carry; + uint16_t hours_carry; + + sum = ((uint16_t) clock->seconds) + ((uint16_t) seconds); + if (sum >= 60) { + minutes_carry = sum / 60; + clock->seconds = sum % 60; + + sum = ((uint16_t) clock->minutes) + minutes_carry; + if (sum >= 60) { + hours_carry = sum / 60; + clock->minutes = sum % 60; + + sum = ((uint16_t) clock->hours) + hours_carry; + if (sum >= 12) { + } + } + else { + clock->minutes = sum; + } + } + else { + clock->seconds = sum; + } +} + +void print_time(twleve_hour_clock_t *clock) +{ + printf("%2u:%02u:%02u %2s", clock->hours, clock->minutes, clock->seconds, meridiem_text(clock->meridiem)); +} + +void reprint_time(twleve_hour_clock_t *clock) +{ + printf("\b\b\b\b\b\b\b\b\b\b\b"); + print_time(clock); +} + diff --git a/12hourclk.h b/12hourclk.h new file mode 100644 index 0000000..44b2ba5 --- /dev/null +++ b/12hourclk.h @@ -0,0 +1,24 @@ +#ifndef TWELVE_HOUR_CLOCK_H +#define TWELVE_HOUR_CLOCK_H + +#include /* uint8_t */ + +typedef enum { + ANTE_MERIDIEM, POST_MERIDIEM +} meridiem_t; + +typedef struct { + uint8_t hours; + uint8_t minutes; + uint8_t seconds; + meridiem_t meridiem; +} twleve_hour_clock_t; + +extern void read_interactively(twleve_hour_clock_t *clock); +extern void add_one_second(twleve_hour_clock_t *clock); +extern void add_seconds(twleve_hour_clock_t *clock, uint8_t seconds); +extern void print_time(twleve_hour_clock_t *clock); +extern void reprint_time(twleve_hour_clock_t *clock); + +#endif + diff --git a/ALARMCLK.dsk b/ALARMCLK.dsk new file mode 100644 index 0000000..ad55f14 Binary files /dev/null and b/ALARMCLK.dsk differ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..51583c8 --- /dev/null +++ b/Makefile @@ -0,0 +1,51 @@ +# Builds the Alarm Clock app +# + +# Requirements: +# 1. Gmake must be used. +# 2. The cc65 compiler must be properly setup. See setup-cc65. +# + +ifndef CC65_TARGET + CC65_TARGET:=apple2enh +endif + +PGM=alarmclk +OBJS=alarmclk.o 12hourclk.o clkfreq.o + +PGM2=cpufreq +OBJS2=clkfreq.o + +CC=cl65 +AS=ca65 + +CFLAGS=-t $(CC65_TARGET) -O +ASFLAGS=-t $(CC65_TARGET) +LDFLAGS=-t $(CC65_TARGET) + +DISK_VOL=ALARMCLK +DISK=$(DISK_VOL).dsk + +AC=java -jar lib/AppleCommander-1.3.5.14.jar +MKDISK=$(AC) -pro140 $(DISK) $(DISK_VOL) + +######################################## + +all: $(DISK) + +$(DISK): $(PGM) $(PGM2) + $(AC) -d $(DISK) $< + $(AC) -cc65 $(DISK) $< BIN < $< + +$(PGM): $(OBJS) + $(CC) $(LDFLAGS) -o $@ $^ + +$(PGM2): clkfreq.s + $(AS) $(ASFLAGS) -o $@ $^ + +# Compile and assemble rules use the defuault rules after CC and CFLAGS +# are set. + +clean: + $(RM) $(PGM) $(PGM2) *.o + diff --git a/alarmclk.c b/alarmclk.c new file mode 100644 index 0000000..23f4ad5 --- /dev/null +++ b/alarmclk.c @@ -0,0 +1,334 @@ +#include /* scanf */ +#include /* uint8_t */ +#include /* true */ +#include /* toupper */ +#include /* clrscr, kbhit */ + +#include "12hourclk.h" +extern void clkfreq(); +extern uint8_t ticks[4]; + +#define CLOCK_FREQUENCY 1023000L +#define CYCLES_PER_NOOP 2 +#define NOOPS_PER_SEC 511500 +#define CTRL_C '\x03' +#define ESC '\x1B' + +void read_inputs(void); +void elapse_one_second(void); +void run_clock(void); + +static twleve_hour_clock_t curr_time; +static twleve_hour_clock_t alarm_time; + +void main(void) +{ + clkfreq(); + printf("%c%c.%c%c%c%c%c%c MHz\n", + ticks[0] & 0x70, + ticks[0] & 0x07, + ticks[1] & 0x70, + ticks[1] & 0x07, + ticks[2] & 0x70, + ticks[2] & 0x07, + ticks[3] & 0x70, + ticks[3] & 0x07); + + read_inputs(); + + clrscr(); + printf("\nAlarm Time: "); + print_time(&alarm_time); + printf("\nCurrent Time: "); + + run_clock(); +} + +void read_inputs() +{ + puts("Current Time"); + read_interactively(&curr_time); + puts("Alarm Time"); + read_interactively(&alarm_time); +} + +void run_clock() +{ + char c; + + print_time(&curr_time); + while (true) { + elapse_one_second(); + add_one_second(&curr_time); + reprint_time(&curr_time); + if (kbhit()) { + c = cgetc(); + if (c == ESC || toupper(c) == 'Q' || c == CTRL_C) { + puts(""); + break; + } + } + } +} + +void elapse_one_second() +{ + int i; + int max_loops; + + max_loops = NOOPS_PER_SEC / 250; + + for (i = 0; i < max_loops; ++i) { + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + } +} + diff --git a/clkfreq.s b/clkfreq.s new file mode 100644 index 0000000..470e928 --- /dev/null +++ b/clkfreq.s @@ -0,0 +1,175 @@ +rgConfig = $6000 ; write: D6=1 - NMI is off, D6=0 - NMI is on +rgStatus = $6000 ; read: D6=0 - UART is busy +rgTxD = $5000 ; write: data to send via UART + +vcNMI = $FFFA + +Refresh = 450 ; NMI rate in Hz + +.export _clkfreq +.export _ticks +_clkfreq: + ldx #NMI + stx vcNMI + sty vcNMI+1 + lda #$40 ; on start NMI is off + sta InUse + +Again: + lda #0 + sta Flag + sta _ticks ; initializing counter + sta _ticks+1 + sta _ticks+2 + sta _ticks+3 + lda #$FE ; initializing NMI counter (zeropoint minus 2 ticks) + sta Timer + lda #$FF + sta Timer+1 + lda InUse ; turn on NMI + and #$BF + sta rgConfig + sta InUse + +L1: bit Flag ; waiting for zeropoint minus 1 tick + bpl L1 + lda #0 + sta Flag + +L2: bit Flag ; waiting for true zeropoint + bpl L2 + lda #0 + sta Flag + +Main: ; main counting cycle +;number of ticks per command sum of ticks +; v v + lda _ticks ;4 + clc ;2 6 + sed ;2 8 + adc #$53 ;2 10 + sta _ticks ;4 14 + lda _ticks+1 ;4 18 + adc #0 ;2 20 + sta _ticks+1 ;4 24 + lda _ticks+2 ;4 28 + adc #0 ;2 30 + sta _ticks+2 ;4 34 + lda _ticks+3 ;4 38 + adc #0 ;2 40 + sta _ticks+3 ;4 44 + cld ;2 46 + bit Flag ;4 50 + bpl Main ;3 53 + + lda #0 ;2 + sta Flag ;4 6 + lda _ticks ;4 10 + clc ;2 12 + sed ;2 14 + adc #$95 ;2 16 + sta _ticks ;4 20 + lda _ticks+1 ;4 24 + adc #0 ;2 26 + sta _ticks+1 ;4 30 + lda _ticks+2 ;4 34 + adc #0 ;2 36 + sta _ticks+2 ;4 40 + lda _ticks+3 ;4 44 + adc #0 ;2 46 + sta _ticks+3 ;4 50 + cld ;2 52 + lda Timer ;4 56 + cmp #Refresh ; 2 + bne Main ; 3 + + lda InUse ; turn off NMI + ora #$40 + sta rgConfig + sta InUse + + ldx #0 ; send first string to the host +L3: lda Mes1,x + beq L4 + jsr Send + inx + jmp L3 + +L4: lda _ticks+3 + pha + lsr + lsr + lsr + lsr + beq L5 ; delete non-significant zero (clock < 10MHz) + jsr PrintDigit +L5: pla + and #15 + jsr PrintDigit + lda #'.' ; decimal point + jsr Send + lda _ticks+2 + jsr PrintTwoDigits + lda _ticks+1 + jsr PrintTwoDigits + lda _ticks + jsr PrintTwoDigits + + ldx #0 ; send second string to the host +L6: lda Mes2,x + beq L7 + jsr Send + inx + jmp L6 +L7: jmp Again ; repeat process + +PrintTwoDigits: + pha + lsr + lsr + lsr + lsr + jsr PrintDigit + pla + and #15 + jsr PrintDigit + rts + +PrintDigit: + ora #$30 + jsr Send + rts + +Send: + bit rgStatus + bvc Send + sta rgTxD + rts + +Mes1: + .byte 13 + .byte "Current clock frequency is " + .byte 0 + +Mes2: + .byte " MHz" + .byte 0 + +_ticks: .res 4,0 +Timer: .res 2,0 +InUse: .byte 0 +Flag: .byte 0 + +NMI: ;6 + pha ;3 9 + inc Timer ;6 15 + bne L8 ;3 18 + inc Timer+1 ; 5 +L8: lda #$80 ;2 20 + sta Flag ;4 24 + pla ;4 28 + rti ;6 34 diff --git a/lib/AppleCommander-1.3.5.14.jar b/lib/AppleCommander-1.3.5.14.jar new file mode 100644 index 0000000..90d3681 Binary files /dev/null and b/lib/AppleCommander-1.3.5.14.jar differ