mirror of
https://github.com/nippur72/apple1-videocard-lib.git
synced 2024-06-09 04:29:32 +00:00
Compare commits
2 Commits
ee8a7e3308
...
c83a357ab6
Author | SHA1 | Date | |
---|---|---|---|
|
c83a357ab6 | ||
|
8f345b801e |
|
@ -1,29 +1,105 @@
|
||||||
# SD CARD COMMANDS
|
# SD CARD
|
||||||
|
|
||||||
## I/O
|
- all numbers must be provided in hexadecimal format unless specified
|
||||||
READ,WRITE for pure binaries,
|
- arguments in `[]` brackets means they are optional
|
||||||
LOAD,BSAVE,RUN for basic/prodos format and .PRG
|
- nested paths are allowed with the `/` character, e.g. `/`, `/foder1/foo`
|
||||||
TYPE
|
- no path given implies current working directory
|
||||||
DUMP
|
|
||||||
|
|
||||||
## FILE
|
## TAGGED FILE NAMES
|
||||||
DEL
|
|
||||||
REN
|
|
||||||
COPY
|
|
||||||
|
|
||||||
## DIR
|
File names containing a tag `#` character have a special meaning: the part after the `#`
|
||||||
DIR
|
indicates the file type (two characters) and the hex loading address (4 characters).
|
||||||
LS
|
|
||||||
CD
|
|
||||||
MKDIR
|
|
||||||
RMDIR
|
|
||||||
|
|
||||||
## MISC
|
`#06` for plain binary files
|
||||||
HELP
|
`#F1` for BASIC programs
|
||||||
JMP
|
|
||||||
BAS
|
E.g.:
|
||||||
STAT
|
`BASIC#06E000` is binary file named `BASIC` that loads at address `$E000`.
|
||||||
MOUNT
|
`STARTREK#F10300` is a BASIC program named `STARTREK` that loads at address `$0300`.
|
||||||
TIME
|
|
||||||
EXIT
|
Tagged file names are used by the `LOAD`, `RUN`, `SAVE` and `DIR` commands to simplify working with files. For example to execute the above files, it's enough to type:
|
||||||
|
|
||||||
|
```
|
||||||
|
LOAD BASIC
|
||||||
|
RUN STARTREK
|
||||||
|
```
|
||||||
|
|
||||||
|
## COMMANDS
|
||||||
|
|
||||||
|
`READ filename startaddress`
|
||||||
|
|
||||||
|
Reads a binary file from the SD card and loads it in memory at the specified address.
|
||||||
|
|
||||||
|
`WRITE filename startaddress endaddress`
|
||||||
|
|
||||||
|
Writes the memory range from `startaddress` to `endaddress` (inclusive) in a file on the SD card.
|
||||||
|
|
||||||
|
`TYPE filename`
|
||||||
|
|
||||||
|
Reads the specified ASCII file from the SD card and prints it on the screen. Press any key to stop the printing and return to the command prompt.
|
||||||
|
|
||||||
|
`DUMP filename [start] [end]`
|
||||||
|
|
||||||
|
Reads the specified binary file from the SD card and prints it on the screen in hexadecimal format. `start` and `end` are optional and are used to print a smaller portion of the file. Press any key to stop the printing and return to the command prompt.
|
||||||
|
|
||||||
|
`LOAD filename`
|
||||||
|
|
||||||
|
Loads a file from the SD card. `filename` refers to a "tagged file name" described above. For convenience, `filename` can be partially given, the first matching file will be loaded.
|
||||||
|
|
||||||
|
`SAVE filename start end`
|
||||||
|
|
||||||
|
Saves a file to the SD card. If `start` and `end` are specified, a binary file with tag `#06` will be created with the memory content from the address range `start`-`end` (included).
|
||||||
|
If `start` and `end` are not specified, the BASIC program currently loaded in memory will be created with the corresponding `#F1` tag.
|
||||||
|
|
||||||
|
`RUN filename`
|
||||||
|
|
||||||
|
Same as `LOAD` but runs the file after loading it. Binary files are exectuted at the starting address specified in the file name tag; BASIC files are `RUN` from the BASIC interpreter.
|
||||||
|
|
||||||
|
`DEL filename`
|
||||||
|
`RM filename`
|
||||||
|
|
||||||
|
Deletes a file from the SD card.
|
||||||
|
|
||||||
|
`DIR [path]`
|
||||||
|
`LS [path]`
|
||||||
|
|
||||||
|
Lists the files from the specified directory, or from the current directory if no path is given. `LS` has a shorter but quicker output format. Press any key to stop the file listing and return to the command prompt.
|
||||||
|
|
||||||
|
`CD path`
|
||||||
|
|
||||||
|
Changes the current working directory to the specified path. The current directory is also shown in the command prompt.
|
||||||
|
|
||||||
|
`MD path`
|
||||||
|
`MKDIR path`
|
||||||
|
|
||||||
|
Creates the specified directory.
|
||||||
|
|
||||||
|
`RD path`
|
||||||
|
`RMDIR path`
|
||||||
|
|
||||||
|
Removes the specified directory. The directory to remove must be empty (no files or directories within).
|
||||||
|
|
||||||
|
`PWD`
|
||||||
|
|
||||||
|
Prints on the screen the current working directory.
|
||||||
|
|
||||||
|
`BAS`
|
||||||
|
|
||||||
|
Prints `LOMEM` and `HIMEM` pointers from the BASIC program currently loaded in memory.
|
||||||
|
|
||||||
|
`JMP address`
|
||||||
|
|
||||||
|
Makes the CPU jump at the specified address.
|
||||||
|
|
||||||
|
`TIME value`
|
||||||
|
|
||||||
|
Set the internal timeout value used in the I/O operations with the SD cards.
|
||||||
|
|
||||||
|
`TEST`
|
||||||
|
|
||||||
|
Internal test.
|
||||||
|
|
||||||
|
`EXIT`
|
||||||
|
|
||||||
|
Exits to the WOZ monitor
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ in Verilog syntax: data = { PORTB[1:0], PORTD[7:2] };
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define FASTWRITE 1
|
// #define FASTWRITE 1
|
||||||
|
|
||||||
#ifdef FASTWRITE
|
#ifdef FASTWRITE
|
||||||
#define get_cpu_strobe ((PORTC >> 1) & 1)
|
#define get_cpu_strobe ((PORTC >> 1) & 1)
|
||||||
|
@ -47,7 +47,8 @@ in Verilog syntax: data = { PORTB[1:0], PORTD[7:2] };
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#include <Regexp.h>
|
// #include <Regexp.h>
|
||||||
|
|
||||||
#include <SPI.h>
|
#include <SPI.h>
|
||||||
#include "SdFat.h"
|
#include "SdFat.h"
|
||||||
|
|
||||||
|
@ -210,6 +211,7 @@ void send_byte_to_cpu(int data) {
|
||||||
const int CMD_READ = 0;
|
const int CMD_READ = 0;
|
||||||
const int CMD_WRITE = 1;
|
const int CMD_WRITE = 1;
|
||||||
const int CMD_DIR = 2;
|
const int CMD_DIR = 2;
|
||||||
|
const int CMD_LOAD = 4;
|
||||||
const int CMD_DEL = 11;
|
const int CMD_DEL = 11;
|
||||||
const int CMD_LS = 12;
|
const int CMD_LS = 12;
|
||||||
const int CMD_CD = 13;
|
const int CMD_CD = 13;
|
||||||
|
@ -218,8 +220,9 @@ const int CMD_PWD = 19;
|
||||||
const int CMD_RMDIR = 15;
|
const int CMD_RMDIR = 15;
|
||||||
const int CMD_TEST = 20;
|
const int CMD_TEST = 20;
|
||||||
|
|
||||||
const int ERR_RESPONSE = 255;
|
const int ERR_RESPONSE = 255;
|
||||||
const int OK_RESPONSE = 0;
|
const int WAIT_RESPONSE = 1;
|
||||||
|
const int OK_RESPONSE = 0;
|
||||||
|
|
||||||
char filename[64];
|
char filename[64];
|
||||||
char tmp[64];
|
char tmp[64];
|
||||||
|
@ -260,6 +263,8 @@ void setup() {
|
||||||
last_dir = -1; // no previous data direction
|
last_dir = -1; // no previous data direction
|
||||||
set_data_port_direction(DIR_INPUT);
|
set_data_port_direction(DIR_INPUT);
|
||||||
|
|
||||||
|
/*
|
||||||
|
// regex disabled for now
|
||||||
MatchState ms;
|
MatchState ms;
|
||||||
char buf [100] = { "The quick " };
|
char buf [100] = { "The quick " };
|
||||||
ms.Target (buf);
|
ms.Target (buf);
|
||||||
|
@ -267,6 +272,7 @@ void setup() {
|
||||||
if(result >0) {
|
if(result >0) {
|
||||||
Serial.println("match!");
|
Serial.println("match!");
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// set working directory to root
|
// set working directory to root
|
||||||
strcpy(cd_path, "/");
|
strcpy(cd_path, "/");
|
||||||
|
@ -400,6 +406,7 @@ void print_dir_entry(File dir, int list_files, int command) {
|
||||||
|
|
||||||
// send file size or directory
|
// send file size or directory
|
||||||
entry.getName(filename, 64);
|
entry.getName(filename, 64);
|
||||||
|
strtoupper(filename);
|
||||||
|
|
||||||
if((list_files == 0 && entry.isDirectory()) || (list_files == 1 && !entry.isDirectory())) {
|
if((list_files == 0 && entry.isDirectory()) || (list_files == 1 && !entry.isDirectory())) {
|
||||||
if(entry.isDirectory()) {
|
if(entry.isDirectory()) {
|
||||||
|
@ -429,16 +436,42 @@ void print_dir_entry(File dir, int list_files, int command) {
|
||||||
send_byte_to_cpu('\r');
|
send_byte_to_cpu('\r');
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// BUG the following line does not work
|
|
||||||
// sprintf(tmp, "%5d %s", entry.size(), filename);
|
char type[5];
|
||||||
// use this instead
|
char address[5];
|
||||||
|
|
||||||
|
strcpy(type,"");
|
||||||
|
strcpy(address, "");
|
||||||
|
|
||||||
|
char *x = strchr(filename, '#');
|
||||||
|
if(x != NULL) {
|
||||||
|
*x++ = 0;
|
||||||
|
if(x[0]=='0' && x[1]=='6') {
|
||||||
|
strcpy(type,"BIN ");
|
||||||
|
strcpy(address,x+2);
|
||||||
|
}
|
||||||
|
else if(x[0]=='F' && x[1]=='1') {
|
||||||
|
strcpy(type,"BAS ");
|
||||||
|
strcpy(address,x+2);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
strcpy(type,"??? ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sprintf(tmp, "%-15s", filename);
|
sprintf(tmp, "%-15s", filename);
|
||||||
print_string_to_cpu(tmp);
|
print_string_to_cpu(tmp);
|
||||||
Serial.print(filename);
|
Serial.print(filename);
|
||||||
|
|
||||||
sprintf(tmp, "%6d", entry.size());
|
sprintf(tmp, "%6d ", entry.size());
|
||||||
print_string_to_cpu(tmp);
|
print_string_to_cpu(tmp);
|
||||||
Serial.println(tmp);
|
Serial.print(tmp);
|
||||||
|
|
||||||
|
print_string_to_cpu(type);
|
||||||
|
Serial.print(type);
|
||||||
|
|
||||||
|
print_string_to_cpu(address);
|
||||||
|
Serial.println(address);
|
||||||
|
|
||||||
send_byte_to_cpu('\r');
|
send_byte_to_cpu('\r');
|
||||||
}
|
}
|
||||||
|
@ -616,6 +649,173 @@ void comando_write() {
|
||||||
send_byte_to_cpu(OK_RESPONSE);
|
send_byte_to_cpu(OK_RESPONSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// **************************************************************************************
|
||||||
|
// **************************************************************************************
|
||||||
|
// ********************************* CMD_LOAD ******************************************
|
||||||
|
// **************************************************************************************
|
||||||
|
// **************************************************************************************
|
||||||
|
|
||||||
|
void comando_load() {
|
||||||
|
Serial.println(F("command CMD_LOAD received from CPU"));
|
||||||
|
|
||||||
|
// reads filename as 0 terminated string
|
||||||
|
receive_string_from_cpu(filename);
|
||||||
|
if(TIMEOUT) return;
|
||||||
|
Serial.print(F("file to read: "));
|
||||||
|
Serial.println(filename);
|
||||||
|
|
||||||
|
// if a matching file name is found, use it
|
||||||
|
if(matchname(filename, tmp)==1) {
|
||||||
|
Serial.print(F("found matching file: "));
|
||||||
|
Serial.println(tmp);
|
||||||
|
strcpy(filename, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!SD.exists(filename)) {
|
||||||
|
Serial.println(F("error opening file"));
|
||||||
|
send_byte_to_cpu(ERR_RESPONSE);
|
||||||
|
send_string_to_cpu(FILE_NOT_FOUND);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// open the file
|
||||||
|
File myFile = SD.open(filename);
|
||||||
|
if(!myFile) {
|
||||||
|
Serial.println(F("error opening file"));
|
||||||
|
send_byte_to_cpu(ERR_RESPONSE);
|
||||||
|
send_string_to_cpu(CANT_OPEN_FILE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Serial.println(F("file opened on the SD card"));
|
||||||
|
|
||||||
|
// ok response
|
||||||
|
send_byte_to_cpu(OK_RESPONSE);
|
||||||
|
if(TIMEOUT) return;
|
||||||
|
Serial.println(F("ok response sent to CPU"));
|
||||||
|
|
||||||
|
// sends matched filename
|
||||||
|
send_string_to_cpu(filename);
|
||||||
|
|
||||||
|
// sends size as low and high byte
|
||||||
|
int size = myFile.size();
|
||||||
|
send_byte_to_cpu(size & 0xFF);
|
||||||
|
send_byte_to_cpu((size >> 8) & 0xFF);
|
||||||
|
if(TIMEOUT) return;
|
||||||
|
Serial.println(F("file size sent to CPU"));
|
||||||
|
|
||||||
|
int bytes_sent = 0;
|
||||||
|
while(myFile.available() && !TIMEOUT) {
|
||||||
|
send_byte_to_cpu(myFile.read());
|
||||||
|
if(!TIMEOUT) bytes_sent++;
|
||||||
|
}
|
||||||
|
myFile.close();
|
||||||
|
|
||||||
|
if(TIMEOUT) {
|
||||||
|
Serial.print(F("timeout, bytes sent: "));
|
||||||
|
Serial.println(bytes_sent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.println(F("file read ok"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void strtoupper(char *str){
|
||||||
|
int len = strlen(str), i;
|
||||||
|
|
||||||
|
for(i=0;i<len;i++)
|
||||||
|
if(str[i]>='a' && str[i]<='z')
|
||||||
|
str[i] = str[i]-'a'+'A';
|
||||||
|
}
|
||||||
|
|
||||||
|
// splits filename into file_path and file_name
|
||||||
|
// e.g. "root/myfolder/pluto" => "root/myfolder" , "pluto"
|
||||||
|
// "myfolder/pluto" => "myfolder", "pluto"
|
||||||
|
// "pluto" => "", "pluto"
|
||||||
|
// "/pluto" => "/", "pluto"
|
||||||
|
|
||||||
|
char file_path[64];
|
||||||
|
char file_name[64];
|
||||||
|
|
||||||
|
void split_path(char *filename) {
|
||||||
|
strcpy(file_path, filename);
|
||||||
|
|
||||||
|
for(int t=strlen(file_path)-1;t>0;t--) {
|
||||||
|
if(file_path[t] == '/') {
|
||||||
|
file_path[t] = 0;
|
||||||
|
strcpy(file_name, &file_path[t+1]);
|
||||||
|
if(t==0) strcpy(file_path, "/"); // case of root folder
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
strcpy(file_path, "");
|
||||||
|
strcpy(file_name, filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// returns in dest the first file that matches (starts with) "filename"
|
||||||
|
// returns 1 if matching file is found
|
||||||
|
// returns 0 if no matching file is found
|
||||||
|
//
|
||||||
|
int matchname(char *filename, char *dest) {
|
||||||
|
// split filename into file_path and file_name
|
||||||
|
split_path(filename);
|
||||||
|
|
||||||
|
Serial.print(F("after split file_path="));
|
||||||
|
Serial.print(file_path);
|
||||||
|
Serial.print(F(", file_name="));
|
||||||
|
Serial.println(file_name);
|
||||||
|
|
||||||
|
if(strlen(file_path)==0) Serial.println(F("scanning the current directory"));
|
||||||
|
else Serial.println(F("scanning the file_path directory"));
|
||||||
|
|
||||||
|
// open the directory containing the file
|
||||||
|
File dir = SD.open(strlen(file_path)==0 ? cd_path : file_path);
|
||||||
|
|
||||||
|
if(!dir) return 0;
|
||||||
|
|
||||||
|
Serial.println(F("dir opened"));
|
||||||
|
|
||||||
|
// scan all the directory
|
||||||
|
while(1) {
|
||||||
|
|
||||||
|
send_byte_to_cpu(WAIT_RESPONSE);
|
||||||
|
if(TIMEOUT) return 0;
|
||||||
|
|
||||||
|
File F = dir.openNextFile();
|
||||||
|
|
||||||
|
// end of directory
|
||||||
|
if(!F) {
|
||||||
|
dir.close();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy filename in dest and closes it
|
||||||
|
F.getName(dest, 64);
|
||||||
|
strtoupper(dest);
|
||||||
|
F.close();
|
||||||
|
|
||||||
|
Serial.println(F("file entry:"));
|
||||||
|
Serial.println(dest);
|
||||||
|
|
||||||
|
// verify the match
|
||||||
|
if(strncmp(file_name, dest, strlen(filename))==0) {
|
||||||
|
Serial.println(F("it is matching!"));
|
||||||
|
// matching, dest already contains the matched file name
|
||||||
|
|
||||||
|
// if file_path is empty then it's current directory, do nothing
|
||||||
|
// else file_path needs to be combined with file name
|
||||||
|
if(file_path[0]!=0) {
|
||||||
|
Serial.println(F("not on current dir, joining paths"));
|
||||||
|
strcpy(filename, dest);
|
||||||
|
if(file_path[0]=='/' && file_path[1]==0) sprintf(dest,"/%s", filename); // case of root folder
|
||||||
|
else sprintf(dest,"%s/%s", file_path, filename); // case of normal nested folder
|
||||||
|
}
|
||||||
|
dir.close();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// **************************************************************************************
|
// **************************************************************************************
|
||||||
// **************************************************************************************
|
// **************************************************************************************
|
||||||
// ********************************* CMD_DEL ********************************************
|
// ********************************* CMD_DEL ********************************************
|
||||||
|
@ -867,6 +1067,7 @@ void loop() {
|
||||||
|
|
||||||
if(data == CMD_READ) comando_read();
|
if(data == CMD_READ) comando_read();
|
||||||
else if(data == CMD_WRITE) comando_write();
|
else if(data == CMD_WRITE) comando_write();
|
||||||
|
else if(data == CMD_LOAD) comando_load();
|
||||||
else if(data == CMD_DEL) comando_del();
|
else if(data == CMD_DEL) comando_del();
|
||||||
else if(data == CMD_RMDIR) comando_rmdir();
|
else if(data == CMD_RMDIR) comando_rmdir();
|
||||||
else if(data == CMD_MKDIR) comando_mkdir();
|
else if(data == CMD_MKDIR) comando_mkdir();
|
||||||
|
|
|
@ -6,30 +6,109 @@
|
||||||
|
|
||||||
// global cmd
|
// global cmd
|
||||||
|
|
||||||
void comando_load() {
|
void comando_load_bas() {
|
||||||
|
|
||||||
// send command byte
|
// send command byte
|
||||||
send_byte_to_MCU(CMD_READ);
|
send_byte_to_MCU(CMD_LOAD);
|
||||||
if(TIMEOUT) return;
|
if(TIMEOUT) return;
|
||||||
|
|
||||||
// send filename
|
// send filename
|
||||||
send_string_to_MCU(filename);
|
send_string_to_MCU(filename);
|
||||||
if(TIMEOUT) return;
|
if(TIMEOUT) return;
|
||||||
|
|
||||||
// response
|
// wait for OK response, MCU sends many WAIT_RESPONSE to avoid TIMEOUT
|
||||||
byte response = receive_byte_from_MCU();
|
while(1) {
|
||||||
if(TIMEOUT) return;
|
byte response = receive_byte_from_MCU();
|
||||||
|
if(TIMEOUT) return;
|
||||||
|
|
||||||
if(response == ERR_RESPONSE) {
|
if(response == ERR_RESPONSE) {
|
||||||
// error with file, print message
|
// error with file, print message
|
||||||
print_string_response();
|
print_string_response();
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
if(response == OK_RESPONSE) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get matching file name
|
||||||
|
receive_string_from_MCU(filename);
|
||||||
|
woz_puts("FOUND ");
|
||||||
|
woz_puts(filename);
|
||||||
|
woz_putc('\r');
|
||||||
|
|
||||||
|
byte filetype = 0;
|
||||||
|
token_ptr = filename;
|
||||||
|
while(1) {
|
||||||
|
if(*token_ptr == '#') {
|
||||||
|
if(token_ptr[1] == '0' && token_ptr[2] == '6') { filetype = 0x06; break; }
|
||||||
|
if(token_ptr[1] == 'F' && token_ptr[2] == '1') { filetype = 0xF1; break; }
|
||||||
|
}
|
||||||
|
if(*token_ptr == 0) break;
|
||||||
|
token_ptr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate start address for 0x06 binary file
|
||||||
|
if(filetype == 0x06) {
|
||||||
|
token_ptr+=2;
|
||||||
|
hex_to_word(token_ptr);
|
||||||
|
start_address = tmpword;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get file length in tmpword
|
// get file length in tmpword
|
||||||
receive_word_from_mcu();
|
receive_word_from_mcu();
|
||||||
if(TIMEOUT) return;
|
if(TIMEOUT) return;
|
||||||
|
|
||||||
|
if(filetype != 0x06 && filetype != 0xF1) {
|
||||||
|
woz_puts("?INVALID FILE NAME TAG #");
|
||||||
|
for(word t=0;t!=tmpword;t++) receive_byte_from_MCU(); // empty buffer
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
woz_puts("LOADING\r");
|
||||||
|
|
||||||
|
if(filetype == 0x06) {
|
||||||
|
// 0x06 BINARY FILE format
|
||||||
|
|
||||||
|
// get file bytes
|
||||||
|
token_ptr = (byte *) start_address;
|
||||||
|
for(word t=0;t!=tmpword;t++) {
|
||||||
|
byte data = receive_byte_from_MCU();
|
||||||
|
if(TIMEOUT) return;
|
||||||
|
*token_ptr++ = data;
|
||||||
|
|
||||||
|
#ifdef LOADING_DOTS
|
||||||
|
if(((byte)t) == 0) woz_putc('.');
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// decrease by one for display result
|
||||||
|
token_ptr--;
|
||||||
|
|
||||||
|
// print feedback to user
|
||||||
|
woz_putc('\r');
|
||||||
|
woz_puts(filename);
|
||||||
|
woz_putc('\r');
|
||||||
|
woz_print_hexword(start_address);
|
||||||
|
woz_putc('.');
|
||||||
|
woz_print_hexword((word)token_ptr);
|
||||||
|
woz_puts(" (");
|
||||||
|
utoa(tmpword, filename, 10); // use filename as string buffer
|
||||||
|
woz_puts(filename);
|
||||||
|
woz_puts(" BYTES)\rOK");
|
||||||
|
|
||||||
|
// executes machine language program at start address
|
||||||
|
if(cmd == CMD_RUN) {
|
||||||
|
woz_putc('\r');
|
||||||
|
tmpword = start_address;
|
||||||
|
asm {
|
||||||
|
jmp (tmpword)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0xF1 BASIC FILE TYPE
|
||||||
|
|
||||||
// get file bytes
|
// get file bytes
|
||||||
token_ptr = (byte *) 0;
|
token_ptr = (byte *) 0;
|
||||||
for(word t=0;t!=tmpword;t++) {
|
for(word t=0;t!=tmpword;t++) {
|
||||||
|
@ -37,7 +116,9 @@ void comando_load() {
|
||||||
if(TIMEOUT) return;
|
if(TIMEOUT) return;
|
||||||
|
|
||||||
if((t==0 && data!=0x41) || (t==1 && data!=0x31)) {
|
if((t==0 && data!=0x41) || (t==1 && data!=0x31)) {
|
||||||
woz_puts("?NOT CFFA1/PRODOS FORMAT");
|
woz_puts("?UNKNOWN FILE FORMAT");
|
||||||
|
t=t+1;
|
||||||
|
for(;t!=tmpword;t++) receive_byte_from_MCU(); // empty buffer
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if(t<0x004a) {
|
else if(t<0x004a) {
|
||||||
|
@ -81,14 +162,15 @@ void bas_file_info() {
|
||||||
// print feedback to user
|
// print feedback to user
|
||||||
woz_putc('\r');
|
woz_putc('\r');
|
||||||
woz_puts(filename);
|
woz_puts(filename);
|
||||||
woz_puts(": ");
|
woz_putc('\r');
|
||||||
bas_info();
|
bas_info();
|
||||||
woz_puts("\rOK");
|
woz_puts("\rOK");
|
||||||
}
|
}
|
||||||
|
|
||||||
void bas_info() {
|
void bas_info() {
|
||||||
woz_puts("LOMEM=");
|
woz_puts("(LOMEM=");
|
||||||
woz_print_hexword((word) *BASIC_LOMEM);
|
woz_print_hexword((word) *BASIC_LOMEM);
|
||||||
woz_puts(" HIMEM=");
|
woz_puts(" HIMEM=");
|
||||||
woz_print_hexword((word) *BASIC_HIMEM);
|
woz_print_hexword((word) *BASIC_HIMEM);
|
||||||
|
woz_putc(')');
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ void comando_read() {
|
||||||
// print feedback to user
|
// print feedback to user
|
||||||
woz_putc('\r');
|
woz_putc('\r');
|
||||||
woz_puts(filename);
|
woz_puts(filename);
|
||||||
woz_puts(": ");
|
woz_putc('\r');
|
||||||
woz_print_hexword(start_address);
|
woz_print_hexword(start_address);
|
||||||
woz_putc('.');
|
woz_putc('.');
|
||||||
woz_print_hexword((word)token_ptr);
|
woz_print_hexword((word)token_ptr);
|
||||||
|
|
|
@ -1,11 +1,20 @@
|
||||||
// global len
|
// global len
|
||||||
|
|
||||||
void comando_save() {
|
void comando_save_bas() {
|
||||||
|
|
||||||
|
if(((word) *BASIC_HIMEM) < ((word) *BASIC_LOMEM)) {
|
||||||
|
woz_puts("?NO BASIC PROGRAM");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// send command byte
|
// send command byte
|
||||||
send_byte_to_MCU(CMD_WRITE);
|
send_byte_to_MCU(CMD_WRITE);
|
||||||
if(TIMEOUT) return;
|
if(TIMEOUT) return;
|
||||||
|
|
||||||
|
strcat(filename, "#F1");
|
||||||
|
tmpword = (word) *BASIC_LOMEM;
|
||||||
|
append_hex_tmpword(filename);
|
||||||
|
|
||||||
// send filename
|
// send filename
|
||||||
send_string_to_MCU(filename);
|
send_string_to_MCU(filename);
|
||||||
if(TIMEOUT) return;
|
if(TIMEOUT) return;
|
||||||
|
@ -19,6 +28,8 @@ void comando_save() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
woz_puts("SAVING\r");
|
||||||
|
|
||||||
// send file size
|
// send file size
|
||||||
//tmpword = ((word) *BASIC_HIMEM) - ((word)*BASIC_LOMEM) + 512;
|
//tmpword = ((word) *BASIC_HIMEM) - ((word)*BASIC_LOMEM) + 512;
|
||||||
// in assembly:
|
// in assembly:
|
||||||
|
|
|
@ -60,7 +60,7 @@ void comando_write() {
|
||||||
// print feedback to user
|
// print feedback to user
|
||||||
woz_putc('\r');
|
woz_putc('\r');
|
||||||
woz_puts(filename);
|
woz_puts(filename);
|
||||||
woz_puts(": ");
|
woz_puts(":\r");
|
||||||
woz_print_hexword(start_address);
|
woz_print_hexword(start_address);
|
||||||
woz_putc('.');
|
woz_putc('.');
|
||||||
woz_print_hexword(end_address);
|
woz_print_hexword(end_address);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdlib.h>
|
#include <string.h>
|
||||||
|
|
||||||
byte **const BASIC_LOMEM = (byte **) 0x004a; // lomem pointer used by integer BASIC
|
byte **const BASIC_LOMEM = (byte **) 0x004a; // lomem pointer used by integer BASIC
|
||||||
byte **const BASIC_HIMEM = (byte **) 0x004c; // himem pointer used by integer BASIC
|
byte **const BASIC_HIMEM = (byte **) 0x004c; // himem pointer used by integer BASIC
|
||||||
|
@ -15,8 +15,9 @@ byte *const filename = (byte *) (KEYBUFSTART+KEYBUFLEN+6 ); // [33] stores a
|
||||||
byte *const hex1 = (byte *) (KEYBUFSTART+KEYBUFLEN+6+33 ); // [5] stores a hex parameter
|
byte *const hex1 = (byte *) (KEYBUFSTART+KEYBUFLEN+6+33 ); // [5] stores a hex parameter
|
||||||
byte *const hex2 = (byte *) (KEYBUFSTART+KEYBUFLEN+6+33+5); // [5] stores a hex parameter
|
byte *const hex2 = (byte *) (KEYBUFSTART+KEYBUFLEN+6+33+5); // [5] stores a hex parameter
|
||||||
|
|
||||||
const byte OK_RESPONSE = 0x00;
|
const byte OK_RESPONSE = 0x00;
|
||||||
const byte ERR_RESPONSE = 0xFF;
|
const byte WAIT_RESPONSE = 0x01;
|
||||||
|
const byte ERR_RESPONSE = 0xFF;
|
||||||
|
|
||||||
// command constants, which are also byte commands to send to the MCU
|
// command constants, which are also byte commands to send to the MCU
|
||||||
const byte CMD_READ = 0;
|
const byte CMD_READ = 0;
|
||||||
|
@ -127,6 +128,27 @@ void hex_to_word(byte *str) {
|
||||||
if(i>4 || i==0) hex_to_word_ok = 0;
|
if(i>4 || i==0) hex_to_word_ok = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void strcat(char *dest, char *src) {
|
||||||
|
while(*dest) dest++;
|
||||||
|
while(*src) *dest++ = *src++;
|
||||||
|
*dest = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void append_hex_digit(char *dest, byte digit) {
|
||||||
|
while(*dest) dest++;
|
||||||
|
if(digit<10) digit += '0';
|
||||||
|
else digit += 'A' - 10;
|
||||||
|
*dest++ = digit;
|
||||||
|
*dest = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void append_hex_tmpword(char *dest) {
|
||||||
|
append_hex_digit(dest, *((byte *)&tmpword+1) >> 4);
|
||||||
|
append_hex_digit(dest, *((byte *)&tmpword+1) & 0x0F);
|
||||||
|
append_hex_digit(dest, *((byte *)&tmpword+0) >> 4);
|
||||||
|
append_hex_digit(dest, *((byte *)&tmpword+0) & 0x0F);
|
||||||
|
}
|
||||||
|
|
||||||
#include "cmd_read.h"
|
#include "cmd_read.h"
|
||||||
#include "cmd_write.h"
|
#include "cmd_write.h"
|
||||||
#include "cmd_load.h"
|
#include "cmd_load.h"
|
||||||
|
@ -238,7 +260,7 @@ void console() {
|
||||||
woz_puts("?MISSING FILENAME");
|
woz_puts("?MISSING FILENAME");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
comando_load();
|
comando_load_bas();
|
||||||
}
|
}
|
||||||
else if(cmd == CMD_SAVE) {
|
else if(cmd == CMD_SAVE) {
|
||||||
get_token(filename, 32); // parse filename
|
get_token(filename, 32); // parse filename
|
||||||
|
@ -246,7 +268,33 @@ void console() {
|
||||||
woz_puts("?MISSING FILENAME");
|
woz_puts("?MISSING FILENAME");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
comando_save();
|
//comando_save();
|
||||||
|
|
||||||
|
get_token(hex1, 4);
|
||||||
|
if(hex1[0] != 0) {
|
||||||
|
// it's SAVE binary file
|
||||||
|
hex_to_word(hex1);
|
||||||
|
if(!hex_to_word_ok) {
|
||||||
|
woz_puts("?BAD ADDRESS");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
start_address = tmpword;
|
||||||
|
|
||||||
|
strcat(filename, "#06");
|
||||||
|
append_hex_tmpword(filename);
|
||||||
|
|
||||||
|
get_token(hex2, 4);
|
||||||
|
hex_to_word(hex2);
|
||||||
|
if(!hex_to_word_ok) {
|
||||||
|
woz_puts("?BAD ADDRESS");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
end_address = tmpword;
|
||||||
|
comando_write();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
comando_save_bas();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if(cmd == CMD_TYPE) {
|
else if(cmd == CMD_TYPE) {
|
||||||
get_token(filename, 32); // parse filename
|
get_token(filename, 32); // parse filename
|
||||||
|
|
|
@ -121,6 +121,16 @@ void send_string_to_MCU(char *msg) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// receive a string sent by the MCU
|
||||||
|
void receive_string_from_MCU(char *dest) {
|
||||||
|
while(1) {
|
||||||
|
byte data = receive_byte_from_MCU();
|
||||||
|
*dest++ = data;
|
||||||
|
if(TIMEOUT) break;
|
||||||
|
if(data == 0) break; // string terminator
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// print a string sent by the MCU
|
// print a string sent by the MCU
|
||||||
void print_string_response() {
|
void print_string_response() {
|
||||||
while(1) {
|
while(1) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user