Compare commits

...

13 Commits

Author SHA1 Message Date
nino-porcino f83bda47df adapt VIACLOCK to Replica-1 2022-06-03 14:36:25 +02:00
nino-porcino 4631eda4c7 tools for splitting the Replica-1 eprom 2022-06-03 10:27:26 +02:00
nino-porcino 41336bea43 tool for converting PDOS basic files to .prg 2022-06-03 10:26:54 +02:00
nino-porcino 60ea106be3 skip build step for NOKUKEBOX 2022-06-03 10:26:27 +02:00
nino-porcino 4f6b138849 add ram test programs 2022-06-03 10:25:31 +02:00
nino-porcino 687832c5fc add Anagram & Hangman 2022-06-03 10:21:45 +02:00
nino-porcino ab3d431795 increase version number 2022-06-03 09:57:47 +02:00
nino-porcino f2b530f048 reset VIA after timeout 2022-06-03 09:57:34 +02:00
nino-porcino 236b956aec fix TEST command 2022-06-03 09:57:21 +02:00
nino-porcino 132dca24e6 print entry points for applesoft basic 2022-06-03 09:56:39 +02:00
nino-porcino ad26e572e0 fix EXIT command bug 2022-06-03 09:33:05 +02:00
nino-porcino c388f8bcd0 add integer basic warm start reference 2022-06-03 09:29:54 +02:00
nino-porcino fbf6b01af0 increase to 64 chars buffer, use stack variables 2022-06-03 09:29:03 +02:00
19 changed files with 3833 additions and 23 deletions

167
demos/anagram/anagram.c Normal file
View File

@ -0,0 +1,167 @@
#include <string.h>
#include <utils.h>
#include <apple1.h>
#include <stdlib.h>
#include "words.h" // vocabulary of words
char *the_word; // the word to guess
char scrambled[MAXWORDLEN+1]; // the word with scrambled letters
char buf[16]; // string buffer containing the number of the score
unsigned int score; // keeps score (accumulated length of guessed words)
__address(0x03) unsigned long int time = 0; // keeps track of time
__address(0x04) unsigned int time_high; // high word of the time counter
unsigned int timeout;
byte len;
#define LETTERSCORE (150)
// gets a key, increment 32 bit timer and randomize seed
byte getkey() {
byte k = apple1_readkey();
if(k!=0) return k;
// increment 32 bit timer
asm {
inc time
bne inc_end
inc time+1
bne inc_end
inc time+2
bne inc_end
inc time+3
inc_end:
}
// randomize random seed
rand_state++;
if(rand_state == 0) rand_state = 1; // avoid 0 state for the LFSR
return 0;
}
// pick the word to guess randomly from the vocabulary
char *pick_random_word() {
unsigned int index;
do index = rand() & 0x7fff; while(index>=NUMWORDS);
return words[index];
}
// pick a random letter within the word
byte pick_random_letter(byte l) {
byte index;
do index = rand() & 31; while(index>=l);
return index;
}
// scramble the word to guess
void scramble_word() {
strcpy(scrambled, the_word);
len = strlen(scrambled);
// permute each letter of the word with a random position
for(byte x=0;x<len;x++) {
byte y = pick_random_letter(len); // gets a random position
// do the letter swapping
byte c = scrambled[x];
scrambled[x] = scrambled[y];
scrambled[y] = c;
}
}
byte game_loop() {
the_word = pick_random_word(); // picks a random word
scramble_word(); // and scrambles it
// calculate timeout
timeout = 0;
for(byte t=0;t<len;t++) {
timeout += LETTERSCORE;
}
time = 0; // reset time
byte x = 0; // position of letter guessed correctly
// display the scrambled word
woz_puts("\r\r>>> ");
woz_puts(scrambled);
woz_puts(" <<< \r\r");
// loop that asks for a letter and counts time
while(1) {
byte k = getkey();
if(k) {
if(k==27) return 2; // ESC quits the game
// if letter is correct, display and advance
if(k==the_word[x]) {
woz_putc(k);
x = x + 1;
if(the_word[x] == 0) return 1; // whole word guessed correctly, game completed
}
else {
// wrong letter, time penalty
time_high += (LETTERSCORE/2);
}
}
else {
// check if time elapsed
if(time_high > timeout) break;
}
}
return 0;
}
void game() {
//woz_puts("\r\rGUESS THE WORDS!");
score = 0;
while(1) {
byte result = game_loop();
if(result==1) {
score += strlen(the_word);
utoa(score, buf, 10);
woz_puts("\r\rCORRECT! SCORE: ");
woz_puts(buf);
}
else if(result==0) {
woz_puts("\r\rOUT OF TIME!!! - YOU LOOSE\r\r");
woz_puts("THE WORD WAS: ");
woz_puts(the_word);
break;
}
else break; // result == 2, ESC pressed
}
utoa(score, buf, 10);
woz_puts("\r\rFINAL SCORE: ");
woz_puts(buf);
woz_puts("\r\r");
}
void main() {
woz_puts("\r\r*** THE ANAGRAM GAME ***");
woz_puts("\r\rGUESS THE WORD BEFORE TIME RUNS OUT");
woz_puts("\r\rTIME PENALTY FOR WRONG LETTERS");
woz_puts("\r\rPRESS ANY KEY TO START ");
while(!getkey()); // randomize while waiting for a key
while(1) {
game();
woz_puts("PLAY AGAIN? ");
byte k;
do k = apple1_getkey(); while(k!='N' && k!='Y');
if(k=='N') break;
}
woz_puts("\r\rGAME WRITTEN BY ANTONINO PORCINO\r\rBYE!\r\r");
woz_mon();
}

208
demos/anagram/hangman.c Normal file
View File

@ -0,0 +1,208 @@
#define APPLE1_USE_WOZ_MONITOR 1
#include <string.h>
#include <utils.h>
#include <apple1.h>
#include <stdlib.h>
#include "words.h" // vocabulary of words
char *the_word; // the complete word to guess
char partial[MAXWORDLEN+1]; // the partial word guessed by the user with "_"
char keybuf[MAXWORDLEN+1]; // keyboard buffer
char len; // the length of the word
char hang_state; // status progression of the hang
#define MAX_HANG_STATE 6 // 0=initial, 1=head, 2=body, 3=leftarm, 4=left leg, 5=right arm, 6=right leg
// gets a key and randomize seed
byte getkey() {
byte k = apple1_readkey();
if(k!=0) return k;
// randomize random seed
rand_state++;
if(rand_state == 0) rand_state = 1; // avoid 0 state for the LFSR
return 0;
}
// pick the word to guess randomly from the vocabulary
char *pick_random_word() {
unsigned int index;
do index = rand() & 0x7fff; while(index>=NUMWORDS);
return words[index];
}
// 012345678901234567
//0 XXXXXXXXXXX
//1 X / !
//2 X / O
//3 X/ /#\
//4 X / \
//5 X
//6 X
//7~~~~~~~~~~~~~~~~~~~~~~
//
char L0[20];
char L1[20];
char L2[20];
char L3[20];
char L4[20];
char L5[20];
char L6[20];
char L7[20];
void print_hangman() {
strcpy(L0, " ___________");
strcpy(L1, " ! / ");
strcpy(L2, " ! / ");
strcpy(L3, " !/ ");
strcpy(L4, " ! ");
strcpy(L5, " !");
strcpy(L6, " !");
strcpy(L7, "~~~+~~~~~~~~~~~~~~~");
if(hang_state >= 1) {
L1[13] = '!';
L2[13] = 'O';
}
if(hang_state >= 2) {
L3[13] = 'X';
}
if(hang_state >= 3) {
L3[12] = '/';
}
if(hang_state >= 4) {
L4[12] = '/';
}
if(hang_state >= 5) {
L3[14] = '\\';
}
if(hang_state >= 6) {
L4[14] = '\\';
}
/*
woz_puts("\rhang_state:");
woz_print_hex(hang_state);
woz_putc('\r');
*/
woz_puts("\r\r");
woz_puts(L0); woz_putc('\r');
woz_puts(L1); woz_putc('\r');
woz_puts(L2); woz_putc('\r');
woz_puts(L3); woz_putc('\r');
woz_puts(L4); woz_putc('\r');
woz_puts(L5); woz_putc('\r');
woz_puts(L6); woz_putc('\r');
woz_puts(L6); woz_putc('\r');
woz_puts(L7); woz_putc('\r');
woz_putc('\r');
}
void print_word() {
woz_puts("\r\rWORD: ");
woz_puts(partial);
woz_puts("\r\r");
}
byte game_loop() {
byte t;
// picks a random word
the_word = pick_random_word();
len = strlen(the_word);
// reset partial word
strcpy(partial, the_word);
for(t=0;t<len;t++) partial[t] = '_';
// display the initial hangman
hang_state = 0;
print_hangman();
while(1) {
print_word(); // display the partial word
apple1_input_line_prompt(keybuf, len);
t = strlen(keybuf);
if(t == 1) {
// one letter guess
byte found = 0;
char c = keybuf[0];
for(t=0;t<len;t++) {
char q = the_word[t];
if(q==c && partial[t] == '_') {
partial[t] = c;
found = 1;
}
}
if(found == 0) {
woz_puts("\r\rWRONG !!!\r\r");
hang_state++;
print_hangman();
if(hang_state == MAX_HANG_STATE) return 0; // game over: man hanged
}
else {
if(strcmp(the_word,partial)==0) {
print_word();
return 1; // game over: word guessed
}
}
}
else if(t == len) {
// guess the whole word
if(strcmp(the_word,keybuf)==0) {
strcpy(partial, keybuf);
print_word();
return 1; // game over: word guessed
}
}
}
return 0;
}
void game() {
while(1) {
byte result = game_loop();
if(result==1) {
woz_puts("\r\rCORRECT! YOU SAVED THE MAN!!");
break;
}
else if(result==0) {
woz_puts("\r\rNOOO, HE'S DEAD NOW!\r\r");
woz_puts("THE WORD WAS: ");
woz_puts(the_word);
break;
}
else break; // result == 2, ESC pressed
}
woz_puts("\r\r");
}
void main() {
woz_puts("\r\r*** HANGMAN ***");
woz_puts("\r\rSAVE THE MAN BY GUESSING THE WORD\r\r");
while(!getkey()); // randomize while waiting for a key
while(1) {
game();
woz_puts("PLAY AGAIN? ");
byte k;
do k = apple1_getkey(); while(k!='N' && k!='Y');
if(k=='N') break;
}
woz_puts("\r\rGAME WRITTEN BY ANTONINO PORCINO\r\rBYE!\r\r");
woz_mon();
}

10
demos/anagram/m.bat Normal file
View File

@ -0,0 +1,10 @@
@set TARGET=NOJUKEBOX
@call ..\..\tools\build anagram
copy out\anagram.prg ..\..\..\apple1-emu\software\anagram.prg /y
copy out\anagram.bin ..\..\..\apple1-emu\software\sdcard_image\PLAB\ANAGRAM#060280 /y
@set TARGET=NOJUKEBOX
@call ..\..\tools\build hangman
copy out\hangman.prg ..\..\..\apple1-emu\software\hangman.prg /y
copy out\hangman.bin ..\..\..\apple1-emu\software\sdcard_image\PLAB\HANGMAN#060280 /y

3020
demos/anagram/mkwords.js Normal file

File diff suppressed because it is too large Load Diff

6
demos/anagram/words.h Normal file

File diff suppressed because one or more lines are too long

58
demos/checksum/checksum.c Normal file
View File

@ -0,0 +1,58 @@
//#pragma start_address(0x8000)
#define APPLE1_USE_WOZ_MONITOR 1
#define INPUT_LINE_PROMPT_CHAR '?'
#include <string.h>
#include <utils.h>
#include <apple1.h>
#include <stdlib.h>
byte *const KEYBUF = (byte *) 0x0200; // use the same keyboard buffer as in WOZ monitor
unsigned int start_address;
unsigned int end_address;
unsigned int check_sum;
unsigned int hex_to_word(byte *str) {
unsigned int tmpword=0;
byte hex_to_word_ok = 1;
byte c;
byte i;
for(i=0; c=str[i]; ++i) {
tmpword = tmpword << 4;
if(c>='0' && c<='9') tmpword += (c-'0');
else if(c>='A' && c<='F') tmpword += (c-65)+0x0A;
else hex_to_word_ok = 0;
}
if(i>4 || i==0) hex_to_word_ok = 0;
return tmpword;
}
void main() {
woz_puts("\r\r*** CHECKSUM ***\r");
while(1) {
woz_puts("\rSTART ADDRESS "); apple1_input_line_prompt(KEYBUF, 4); if(KEYBUF[0]!=0) start_address = hex_to_word(KEYBUF);
woz_puts("\rEND ADDRESS "); apple1_input_line_prompt(KEYBUF, 4); if(KEYBUF[0]!=0) end_address = hex_to_word(KEYBUF);
check_sum = 0;
for(unsigned int t=start_address;;t++) {
byte b = *((byte *)t);
check_sum += (unsigned int) b;
if(t==end_address) break;
}
woz_puts("\r\r");
woz_print_hexword(start_address);
woz_putc('-');
woz_print_hexword(end_address);
woz_puts(" => ");
woz_print_hexword(check_sum);
woz_puts(" CHECKSUM\r\r");
}
}

14
demos/checksum/m.bat Normal file
View File

@ -0,0 +1,14 @@
@echo off
call ..\..\tools\build checksum
call ..\..\tools\build ramchk
call ..\..\tools\build ramfill
copy out\checksum.prg ..\..\..\apple1-emu\software\checksum.prg /y
copy out\ramchk.prg ..\..\..\apple1-emu\software\ramchk.prg /y
copy out\ramfill.prg ..\..\..\apple1-emu\software\ramfill.prg /y
copy out\checksum.bin ..\..\..\apple1-emu\software\sdcard_image\PLAB\CHKSUM#060280 /y
copy out\ramchk.bin ..\..\..\apple1-emu\software\sdcard_image\PLAB\RAMCHK#060280 /y
copy out\ramfill.bin ..\..\..\apple1-emu\software\sdcard_image\PLAB\RAMFILL#060280 /y

100
demos/checksum/ramchk.c Normal file
View File

@ -0,0 +1,100 @@
#define APPLE1_USE_WOZ_MONITOR 1
#define INPUT_LINE_PROMPT_CHAR '?'
#include <string.h>
#include <utils.h>
#include <apple1.h>
#include <stdlib.h>
byte *const KEYBUF = (byte *) 0x0200; // use the same keyboard buffer as in WOZ monitor
byte *start_address;
byte *end_address;
unsigned int hex_to_word(byte *str) {
unsigned int tmpword=0;
byte hex_to_word_ok = 1;
byte c;
byte i;
for(i=0; c=str[i]; ++i) {
tmpword = tmpword << 4;
if(c>='0' && c<='9') tmpword += (c-'0');
else if(c>='A' && c<='F') tmpword += (c-65)+0x0A;
else hex_to_word_ok = 0;
}
if(i>4 || i==0) hex_to_word_ok = 0;
return tmpword;
}
// 0 = bad ram
// 1 = good ram
// 2 = rom
byte test_location(byte *ptr) {
byte oldval = *ptr;
*ptr = ~oldval; if(*ptr == oldval) return 2; // ROM found
if(*ptr != ~oldval) return 0;
*ptr = 0; if(*ptr != 0 ) return 0;
*ptr = 255; if(*ptr != 255 ) return 0;
*ptr = (1<<0); if(*ptr != (1<<0) ) return 0;
*ptr = (1<<1); if(*ptr != (1<<1) ) return 0;
*ptr = (1<<2); if(*ptr != (1<<2) ) return 0;
*ptr = (1<<3); if(*ptr != (1<<3) ) return 0;
*ptr = (1<<4); if(*ptr != (1<<4) ) return 0;
*ptr = (1<<5); if(*ptr != (1<<5) ) return 0;
*ptr = (1<<6); if(*ptr != (1<<6) ) return 0;
*ptr = (1<<7); if(*ptr != (1<<7) ) return 0;
*ptr = (~(1<<0)); if(*ptr != (~(1<<0)) ) return 0;
*ptr = (~(1<<1)); if(*ptr != (~(1<<1)) ) return 0;
*ptr = (~(1<<2)); if(*ptr != (~(1<<2)) ) return 0;
*ptr = (~(1<<3)); if(*ptr != (~(1<<3)) ) return 0;
*ptr = (~(1<<4)); if(*ptr != (~(1<<4)) ) return 0;
*ptr = (~(1<<5)); if(*ptr != (~(1<<5)) ) return 0;
*ptr = (~(1<<6)); if(*ptr != (~(1<<6)) ) return 0;
*ptr = (~(1<<7)); if(*ptr != (~(1<<7)) ) return 0;
*ptr = oldval; if(*ptr != oldval) return 0;
return 1; // good ram
}
void main() {
woz_puts("\r\r*** RAM CHECK ***\r");
while(1) {
byte curr_state = 3;
woz_puts("\rSTART ADDRESS "); apple1_input_line_prompt(KEYBUF, 4); start_address = (byte *) hex_to_word(KEYBUF);
woz_puts("\rEND ADDRESS "); apple1_input_line_prompt(KEYBUF, 4); end_address = (byte *) hex_to_word(KEYBUF);
woz_puts("\r\r");
for(byte *t=start_address;;t++) {
byte new_state = test_location(t);
if(new_state != curr_state) {
curr_state = new_state;
woz_putc('\r');
woz_print_hexword((unsigned int )t);
if(curr_state == 0) { woz_puts(" BAD RAM"); curr_state = 3; }
else if(curr_state == 1) woz_puts(" RAM");
else if(curr_state == 2) woz_puts(" ROM");
}
//if(!) {
// woz_print_hexword((unsigned int )t);
// woz_putc(' ');
//}
if(t==end_address) break;
//if((t & 0xFF)==0) woz_putc('.');
}
woz_puts("\r\rDONE\r\r");
}
}

75
demos/checksum/ramfill.c Normal file
View File

@ -0,0 +1,75 @@
#define APPLE1_USE_WOZ_MONITOR 1
#define INPUT_LINE_PROMPT_CHAR '?'
#include <string.h>
#include <utils.h>
#include <apple1.h>
#include <stdlib.h>
byte *const KEYBUF = (byte *) 0x0200; // use the same keyboard buffer as in WOZ monitor
byte *start_address;
byte *end_address;
unsigned int hex_to_word(byte *str) {
unsigned int tmpword=0;
byte hex_to_word_ok = 1;
byte c;
byte i;
for(i=0; c=str[i]; ++i) {
tmpword = tmpword << 4;
if(c>='0' && c<='9') tmpword += (c-'0');
else if(c>='A' && c<='F') tmpword += (c-65)+0x0A;
else hex_to_word_ok = 0;
}
if(i>4 || i==0) hex_to_word_ok = 0;
return tmpword;
}
void main() {
woz_puts("\r\r*** RAM FILL TEST ***\r");
woz_puts("\rSTART ADDRESS "); apple1_input_line_prompt(KEYBUF, 4); start_address = (byte *) hex_to_word(KEYBUF);
woz_puts("\rEND ADDRESS "); apple1_input_line_prompt(KEYBUF, 4); end_address = (byte *) hex_to_word(KEYBUF);
woz_puts("\r\r");
while(1) {
// fill with normal data
rand_state = 1;
for(byte *t=start_address;;t++) {
byte r = (byte) (rand() & 0xFF);
*t = r;
if(t==end_address) break;
}
// verify normal data
rand_state = 1;
for(byte *t=start_address;;t++) {
byte r = (byte) (rand() & 0xFF);
if(*t != r) { woz_print_hexword((unsigned int )t); woz_putc(' '); }
if(t==end_address) break;
}
// fill with inverted data
rand_state = 1;
for(byte *t=start_address;;t++) {
byte r = (byte) (rand() & 0xFF);
*t = ~r;
if(t==end_address) break;
}
// verify inverted data
rand_state = 1;
for(byte *t=start_address;;t++) {
byte r = (byte) (rand() & 0xFF);
if(*t != ~r) { woz_print_hexword((unsigned int )t); woz_putc(' '); }
if(t==end_address) break;
}
woz_putc('.');
}
}

View File

@ -99,6 +99,7 @@ RUN STARTREK
`6000R` AppleSoft BASIC cold start (needed at least once)
`6003R` AppleSoft BASIC warm start (do not destroy the BASIC program in RAM)
`E000R` Integer BASIC cold start
`E2B3R` Integer BASIC warm start
`EFECR` Integer BASIC "RUN" command (can be used as a warm entry point)
`8000R` SD card OS command prompt

View File

@ -224,7 +224,7 @@ const byte OK_RESPONSE = 0;
// @buffer
char filename[64];
char tmp[32];
char tmp[64];
char cd_path[64];
// fixed messages
@ -721,11 +721,7 @@ void strtoupper(char *str){
// "pluto" => "", "pluto"
// "/pluto" => "/", "pluto"
// @buffer
char file_path[64];
char file_name[32];
void split_path(char *filename) {
void split_path(char *filename, char *file_path, char *file_name) {
strcpy(file_path, filename);
for(int t=strlen(file_path)-1;t>0;t--) {
@ -746,8 +742,12 @@ void split_path(char *filename) {
// returns 0 if no matching file is found
//
byte matchname(char *filename, char *dest) {
// @buffer
char file_path[64];
char file_name[64];
// split filename into file_path and file_name
split_path(filename);
split_path(filename, file_path, file_name);
Serial.print(F("after split file_path="));
Serial.print(file_path);

View File

@ -14,6 +14,7 @@ void comando_test() {
drec = receive_byte_from_MCU();
drec ^= 0xff;
if(TIMEOUT) return;
if(drec != dsend) {
woz_puts("\rTRANSFER ERROR\r");
@ -23,7 +24,3 @@ void comando_test() {
if(dsend == 0x00) woz_putc('*');
}
}
void test_via() {
}

View File

@ -45,7 +45,7 @@ const byte CMD_TEST = 20;
const byte CMD_HELP = 21;
const byte CMD_QMARK = 22;
const byte CMD_MOUNT = 23;
const byte CMD_EXIT = 25;
const byte CMD_EXIT = 24;
// the list of recognized commands
byte *DOS_COMMANDS[] = {
@ -187,7 +187,7 @@ void console() {
VIA_init();
woz_puts("\r\r*** SD CARD OS 1.1\r\r");
woz_puts("\r\r*** SD CARD OS 1.2\r\r");
cmd = 0;
@ -436,6 +436,7 @@ void console() {
if(TIMEOUT) {
woz_puts("?I/O ERROR");
TIMEOUT = 0;
VIA_init();
}
}
}

View File

@ -1,2 +1,6 @@
call ..\..\tools\build sdcard
copy out\sdcard.prg ..\..\..\apple1-emu\software\sdcard.prg /y
@grep comando_load_bas out/sdcard.sym
@grep comando_asave out/sdcard.sym
@grep chksum_table out/sdcard.sym

View File

@ -1,3 +1,8 @@
rem @call ..\..\tools\build viatimer
@call ..\..\tools\build viatimer
@call ..\..\tools\build viaclock
copy out\viatimer.bin ..\..\..\apple1-emu\software\sdcard_image\PLAB\VIATIMER#060280 /y
copy out\viaclock.bin ..\..\..\apple1-emu\software\sdcard_image\PLAB\VIACLOCK#060280 /y

View File

@ -13,7 +13,9 @@
#include "..\..\lib\c64font.h"
const word ONE_TICK = 16666; // timer constant for 1/60 second
// const word ONE_TICK = 15996; // timer constant for 1/60 second calculated as 14318180/14*61/65/60
word ONE_TICK;
void enable_timer_interrupt() {
@ -32,6 +34,7 @@ void disable_timer_interrupt() {
}
byte last_min = 0xFF;
byte last_sec = 0xFF;
void print_digit_scanline(byte c, byte y) {
word index = ((word) c-32) * 8 + (word) y;
@ -54,15 +57,34 @@ void print_clock() {
c1 = divr8u(_hours, 10, 0); c2 = rem8u;
c3 = divr8u(_minutes, 10, 0); c4 = rem8u;
woz_puts("\r\r\r\r\r\r\r\r");
for(byte t=0;t<24;t++) woz_putc('\r');
for(byte t=0;t<8;t++) {
print_digit_scanline(c1+'0',t);
print_digit_scanline(c2+'0',t);
print_digit_scanline( ':',t);
print_digit_scanline(c3+'0',t);
print_digit_scanline(c4+'0',t);
}
woz_puts("\r\r\r\r\r\r\r\r");
}
for(byte t=0;t<4;t++) woz_putc('\r');
last_sec = 0;
}
if(last_sec < _seconds) {
//if(last_sec > 20) woz_putc('>');
/*
if(last_sec < 10) { woz_puts("...10 "); last_sec = 10; }
else if(last_sec < 20) { woz_puts("...20 "); last_sec = 20; }
else if(last_sec < 30) { woz_puts("...30 "); last_sec = 30; }
else if(last_sec < 40) { woz_puts("...40 "); last_sec = 40; }
else if(last_sec < 50) { woz_puts("...50 "); last_sec = 50; }
*/
c1 = divr8u(last_sec, 10, 0); c2 = rem8u;
woz_putc(' ');
woz_putc(c1+'0');
woz_putc(c2+'0');
woz_putc(' ');
last_sec++;
}
}
@ -72,19 +94,52 @@ void bye() {
woz_mon();
}
void detect_machine_type() {
// detect if VIA 6522 is present
*VIA_DDRB = 0xA5;
if(*VIA_DDRB != 0xA5) {
woz_puts("\r\rSORRY, THIS PROGRAM NEEDS A VIA 6522 \rMAPPED AT ADDRESS $A000\r\r");
bye();
}
// detect if genuine apple1 or replica-1
woz_puts("\r\rRUNNING ON ");
const word *ptr1 = (word *) 0xF000;
const word *ptr2 = (word *) 0xFF00;
if(*ptr1 == *ptr2) {
// genuine Apple1
ONE_TICK = 15996; // timer constant for 1/60 second calculated as 14318180/14*61/65/60
woz_puts("GENUINE APPLE1");
}
else {
// Replica-1
ONE_TICK = 17045; // timer constant for 1/60 second calculated as 14318180/14/60
woz_puts("APPLE1 REPLICA-1");
}
woz_puts("\r\r");
}
byte *const KEYBUF = (byte *) 0x0200; // use the same keyboard buffer as in WOZ monitor
void main() {
enable_timer_interrupt();
woz_puts("\r\r*** APPLE-1 CLOCK ***\r\r");
woz_puts("\r\r*** APPLE1 CLOCK ***\r\r");
detect_machine_type();
woz_puts("\r\rREQUIRES A VIA 6522 AT $A000\r\r");
woz_puts("\rWHAT TIME IS IT ?\r");
woz_puts("\rWHAT TIME IS IT (HOURS ) "); apple1_input_line_prompt(KEYBUF, 2);
woz_puts("\r(HOURS ) "); apple1_input_line_prompt(KEYBUF, 2);
_hours = (byte) atoi(KEYBUF);
woz_puts("\rWHAT TIME IS IT (MINUTES) "); apple1_input_line_prompt(KEYBUF, 2);
woz_puts("\r(MINUTES) "); apple1_input_line_prompt(KEYBUF, 2);
_minutes = (byte) atoi(KEYBUF);
_seconds = 0;
enable_timer_interrupt();
woz_putc('\r');

View File

@ -3,10 +3,13 @@
@SET FNAME=%1
@SET TMS9918=..\..
@IF "%TARGET%" == "NOJUKEBOX" GOTO NOJUKEBOX
@echo ======================== APPLE 1 JUKEBOX =================================================
call kickc -includedir %TMS9918%\lib -targetdir %TMS9918%\kickc\ -t apple1_jukebox %FNAME%.c -o out\%FNAME%.prg -e
call node %TMS9918%\tools\mkeprom out out\%FNAME%_jukebox.bin
:NOJUKEBOX
@echo ======================== APPLE 1 =================================================
call kickc -includedir %TMS9918%\lib -targetdir %TMS9918%\kickc\ -t apple1 %FNAME%.c -o out\%FNAME%.prg -e -Xassembler="-symbolfile"
call node %TMS9918%\tools\prg2bin -i out\%FNAME%.prg -o out\%FNAME%.bin

67
tools/pdos2prg.js Normal file
View File

@ -0,0 +1,67 @@
const fs = require('fs');
const parseOptions = require("./parseOptions");
const options = parseOptions([
{ name: 'input', alias: 'i', type: String }
]);
if(options.input === undefined) {
console.log("usage: pdos2prg -i inputfile#[...] ");
process.exit(-1);
}
let s = options.input.split("#");
if(s.length != 2) {
console.log("pdos2prg: filename must contain # tag");
process.exit(-1);
}
let tag = s[1];
let start_address = tag.substr(2);
let file_type = tag.substr(0,2).toUpperCase();
let ext = (function(){
if(file_type == "F1") return `_BAS_${start_address}`;
else if(file_type == "F8") return `_ASOFT_${start_address}`;
else return `_BIN_${start_address}`;
})();
let filename = `${s[0]}${ext}.prg`;
start_address = parseInt(start_address,16);
let bin = fs.readFileSync(options.input);
if(file_type == "F1") {
bin = bas2bin(bin, start_address);
start_address = 0x0002;
}
let lo = (start_address >> 0) & 0xFF;
let hi = (start_address >> 8) & 0xFF;
let prg = new Uint8Array([ lo, hi, ...bin ]);
fs.writeFileSync(filename, prg);
console.log(`${filename} written`);
// converts pdos integer basic program
//
// pdos: $0000-$0049 junk
// $004A-$01FF pointers
// $0200-end basic program to relocate at start address
//
// returns:
// $004A-$01FF pointers
// $0200-start-1 filler
// start - end basic program
function bas2bin(data, addr) {
let pointers = data.slice(0x0002, 0x0200);
let prg = data.slice(0x0200);
let diff = new Array(addr - 0x0200).fill(0);
let joined = [ ...pointers, ...diff, ...prg];
return joined;
}

19
tools/splitreplica.js Normal file
View File

@ -0,0 +1,19 @@
const fs = require('fs');
//let bin = fs.readFileSync("replica1-firmware.double-ROM.bin");
let bin = fs.readFileSync("replica1-firmware.double-ROM.modded.bin");
let rom1 = new Uint8Array(bin.slice(0, 0x2000));
let rom2 = new Uint8Array(bin.slice(0x2000, 0x4000));
//fs.writeFileSync("replica.rom1.e000.bin", rom1);
//fs.writeFileSync("replica.rom2.e000.bin", rom2);
fs.writeFileSync("replica.rom1.e000.modded.bin", rom1);
fs.writeFileSync("replica.rom2.e000.modded.bin", rom2);
console.log(`written`);