Fixed issue with IDE. Work on ANSI

Fixed issues with IDE/PATA write. Reworking ANSI support to make it faster and add SGR support.
This commit is contained in:
Peter Weingartner 2021-10-16 00:14:26 -04:00
parent 988114df94
commit a9e0f0c165
10 changed files with 8182 additions and 7963 deletions

View file

@ -43,16 +43,7 @@ short cmd_diskread(short screen, int argc, char * argv[]) {
return -2;
}
for (i = 0; i < 512; i++) {
if (i % 16 == 0) {
print(screen, "\n");
}
print_hex_8(screen, buffer[i]);
print(screen, " ");
}
print(screen, "\n");
dump_buffer(screen, buffer, 512);
return 0;
}

View file

@ -15,6 +15,7 @@
#include "dev/ps2.h"
#include "dev/kbd_mo.h"
#include "dev/text_screen_iii.h"
#include "simpleio.h"
#define ANSI_BUFFER_SIZE 16
#define MAX_ANSI_ARGS 10
@ -27,7 +28,7 @@ typedef void (*ansi_handler)(p_channel, short, short[]);
* Structure to map an ANSI escape sequence pattern to a handler
*/
typedef struct s_ansi_seq {
char * pattern;
char code;
ansi_handler handler;
} t_ansi_seq, *p_ansi_seq;
@ -53,30 +54,136 @@ extern void ansi_ed(p_channel chan, short arg_count, short args[]);
extern void ansi_el(p_channel chan, short arg_count, short args[]);
extern void ansi_ich(p_channel chan, short arg_count, short args[]);
extern void ansi_dch(p_channel chan, short arg_count, short args[]);
extern void ansi_sgr(p_channel chan, short arg_count, short args[]);
/*
* Console variables and constants
*/
/*
* ANSI escape sequences:
* # is a placeholder for any number of numerals
*
* ANSI escape sequences
*/
const t_ansi_seq ansi_sequence[] = {
{ "\x1B[H", ansi_cup },
{ "\x1B[#A", ansi_cuu },
{ "\x1B[#B", ansi_cuf },
{ "\x1B[#C", ansi_cub },
{ "\x1B[#D", ansi_cud },
{ "\x1B[#J", ansi_ed },
{ "\x1B[#K", ansi_el },
{ "\x1B[#@]", ansi_ich },
{ "\x1B[#P]", ansi_dch },
{ "\x1B[#;#H", ansi_cup },
{ '@', ansi_ich },
{ 'A', ansi_cuu },
{ 'B', ansi_cuf },
{ 'C', ansi_cub },
{ 'D', ansi_cud },
{ 'J', ansi_ed },
{ 'K', ansi_el },
{ 'P', ansi_dch },
{ 'H', ansi_cup },
{ 'm', ansi_sgr },
{ 0, 0 }
};
/*
* Return true if a character is an initial character for an ANSI escape code
*
* Inputs:
* c = the character to test
*
* Returns:
* 0 if the character is not an ANSI initial, 1 if it is
*/
short ansi_start_code(char c) {
switch (c) {
case '\x1b':
return 1;
default:
return 0;
}
}
/*
* Find the escape sequence pattern that matches what we've collected.
*
* If one is found, execute it.
* If one is not found, just dump the ANSI buffer
*/
void ansi_match_pattern(p_channel chan, p_console_data con_data) {
char c;
short argc = 0;
int arg[MAX_ANSI_ARGS];
short i, j;
TRACE("ansi_match_pattern");
/* Clear out the argument list */
for (i = 0; i < MAX_ANSI_ARGS; i++) {
arg[i] = 0;
}
/* Make sure we have an escape sequence */
if ((con_data->ansi_buffer[0] != '\x1b') || (con_data->ansi_buffer[1] != '[')) {
/* If not, dump the buffer and return */
con_flush(chan);
return;
}
/* Try to assemble the arguments */
for (i = 2, argc = 0; i < con_data->ansi_buffer_count - 1; i++) {
c = con_data->ansi_buffer[i];
if (isdigit(c)) {
/* If the character is a digit, add it to the current argument */
arg[argc] = arg[argc] * 10 + (c - '0');
} else if (c == ';') {
/* If it's a semi-colon, start the next argument */
argc++;
}
}
argc++;
/* Get the last character... should be the code */
c = con_data->ansi_buffer[con_data->ansi_buffer_count - 1];
/* Try to find the matching escape code */
for (i = 0; ansi_sequence[i].code != 0; i++) {
if (ansi_sequence[i].code == c) {
ansi_handler handler = ansi_sequence[i].handler;
if (handler != 0) {
/* If we found the handler... call it */
handler(chan, argc, arg);
return;
}
}
}
/* We got to the end without a match... dump the buffer */
con_flush(chan);
}
/*
* Add a character to the ANSI buffer... and process when an escape sequence is found
*/
void ansi_process_c(p_channel chan, p_console_data con_data, char c) {
TRACE("ansi_process_c");
if (c == '\x1B') {
/* Start the escape sequence */
con_data->ansi_buffer[0] = c;
con_data->ansi_buffer_count = 1;
} else if (con_data->ansi_buffer_count > 0) {
/* We're processing an escape sequence... add the character to the buffer */
con_data->ansi_buffer[con_data->ansi_buffer_count++] = c;
/* Check to see if we just wrote the trigger */
if (((c >= '@') && (c <= 'Z')) ||
((c >= 'a') && (c <= 'z'))) {
ansi_match_pattern(chan, con_data);
con_data->ansi_buffer_count = 0;
}
} else {
/* Not working on a sequence... so just print it */
text_put_raw(chan->dev, c);
}
}
/*
* ANSI Handler: cursor up
*/
@ -239,6 +346,38 @@ void ansi_dch(p_channel chan, short arg_count, short args[]) {
text_delete(chan->dev, n);
}
/*
* Set Graphics Rendition
*/
void ansi_sgr(p_channel chan, short arg_count, short args[]) {
short i;
TRACE("ansi_sgr");
log_num(LOG_ERROR, "ansi_sgr", arg_count);
for (i = 0; i < arg_count; i++) {
short code = args[i];
log_num(LOG_ERROR, "code = ", code);
if ((code >= 30) && (code <= 37)) {
short foreground = 0, background = 0;
/* Set foreground color */
text_get_color(chan->dev, &foreground, &background);
text_set_color(chan->dev, code - 30, background);
} else if ((code >= 40) && (code <= 47)) {
short foreground = 0, background = 0;
/* Set background color */
text_get_color(chan->dev, &foreground, &background);
text_set_color(chan->dev, foreground, code - 40);
}
}
}
//
// Initialize the console... nothing needs to happen here
//
@ -289,8 +428,11 @@ short con_flush(p_channel chan) {
if (con_data->control & CON_CTRL_ANSI) {
for (i = 0; i < con_data->ansi_buffer_count; i++) {
text_put_raw(chan->dev, con_data->ansi_buffer[i]);
con_data->ansi_buffer[i] = 0;
}
}
con_data->ansi_buffer_count = 0;
return 0;
}
@ -305,120 +447,6 @@ short con_close(p_channel chan) {
return 0;
}
/*
* Return true if a character is an initial character for an ANSI escape code
*
* Inputs:
* c = the character to test
*
* Returns:
* 0 if the character is not an ANSI initial, 1 if it is
*/
short ansi_start_code(char c) {
switch (c) {
case CHAR_ESC:
return 1;
default:
return 0;
}
}
/*
* Attempt to match a pattern to what's in the buffer
* Calls the sequence's handler if the pattern matches
*
* Inputs:
* chan = pointer to the channel record
* con_data = pointer to the console data record for this channel
* sequence = pointer to the ANSI sequence mapping to check
*
* Returns
* 0 if not a match, 1 if it is a match
*/
short ansi_match_pattern(p_channel chan, p_console_data con_data, p_ansi_seq sequence) {
short arg_idx = 0;
short arg[MAX_ANSI_ARGS];
short i, j;
char * pattern = sequence->pattern;
char * buffer = con_data->ansi_buffer;
short buffer_count = con_data->ansi_buffer_count;
for (i = 0, j = 0; i < strlen(pattern); i++) {
if (buffer[j] == pattern[i]) {
/* Character matches... advance to the next character in the buffer and pattern */
j++;
} else if (pattern[i] == '#') {
/* Parse a number of decimal digits */
arg[arg_idx] = 0;
if (buffer[j] == pattern[i+1]) {
/* Parameter is missing... set to zero */
arg_idx++;
} else {
while (isdigit(buffer[j]) && (j < buffer_count)) {
arg[arg_idx] = arg[arg_idx] * 10 + (buffer[j] - '0');
j++;
}
if (j == buffer_count) {
/* This pattern does not match */
return 0;
} else {
/* We've read a number */
arg_idx++;
}
}
} else {
return 0;
}
}
if (i == strlen(pattern)) {
/* The pattern has been completely matched */
/* Clear the buffer */
for (i = 0; i < buffer_count; i++) {
buffer[i] = 0;
}
con_data->ansi_buffer_count = 0;
sequence->handler(chan, arg_idx, arg);
return 1;
}
return 0;
}
/*
* Attempt to match what's in the buffer to known ANSI escape sequences
*
* Inputs:
* chan = pointer to the channel record
* con_data = pointer to the console data record for this channel
*/
void ansi_match_buffer(p_channel chan, p_console_data con_data) {
short arg[MAX_ANSI_ARGS];
short arg_count = 0;
int i;
for (i = 0; i < MAX_ANSI_ARGS; i++) {
arg[i] = 0;
}
for (i = 0; ansi_sequence[i].pattern; i++) {
if (ansi_match_pattern(chan, con_data, &ansi_sequence[i])) {
return;
}
}
/* If not currently matching, but the buffer is full, we need to flush */
if (con_data->ansi_buffer_count == ANSI_BUFFER_SIZE) {
con_flush(chan);
}
}
/*
* Send a byte to the console screen
*/
@ -429,17 +457,7 @@ short con_write_b(p_channel chan, uint8_t b) {
con_data = &(chan->data);
if (con_data->control & CON_CTRL_ANSI) {
/* ANSI codes are to be processed */
if ((con_data->ansi_buffer_count > 0) || ansi_start_code(b)) {
/* We're working on a sequence: add the character to the buffer */
con_data->ansi_buffer[con_data->ansi_buffer_count++] = b;
/* Attempt to match the buffer to an escape sequence */
ansi_match_buffer(chan, con_data);
} else {
/* We're not working on a sequence: just print the character */
text_put_raw(chan->dev, (char)b);
}
ansi_process_c(chan, con_data, (char)b);
} else {
/* Not processing ANSI codes... just pass it to the text driver */

View file

@ -250,7 +250,7 @@ short pata_read(long lba, unsigned char * buffer, short size) {
*PATA_CLDR_LO = (lba >> 8) & 0xff;
*PATA_CLDR_HI = (lba >> 16) & 0xff;
*PATA_CMD_STAT = PATA_CMD_READ_SECTOR; // Issue the READ command
*PATA_CMD_STAT = PATA_CMD_READ_SECTOR; // Issue the READ command 0xE4; //
// TODO: Wait ~500ns
@ -270,6 +270,53 @@ short pata_read(long lba, unsigned char * buffer, short size) {
return i;
}
short pata_flush_cache() {
short i;
unsigned short *wptr;
unsigned char status;
TRACE("pata_write");
if (pata_wait_ready_not_busy()) {
return DEV_TIMEOUT;
}
*PATA_HEAD = 0xe0; // Drive 0
if (pata_wait_ready_not_busy()) {
return DEV_TIMEOUT;
}
*PATA_SECT_SRT = 0; // Set the rest of the LBA
*PATA_CLDR_LO = 0;
*PATA_CLDR_HI = 0;
if (pata_wait_ready_not_busy()) {
return DEV_TIMEOUT;
}
*PATA_CMD_STAT = 0xE7; // PATA_CMD_FLUSH_CACHE;
// Give the controller some time...
for (i = 0; i < 32000; i++) ;
if (pata_wait_ready_not_busy()) {
return DEV_TIMEOUT;
}
status = *PATA_CMD_STAT;
if ((status & PATA_STAT_DF) != 0){
log(LOG_ERROR, "pata_flush_cache: device fault");
return -1;
}
if ((status & PATA_STAT_ERR) != 0) {
log(LOG_ERROR, "pata_flush_cache: error");
return -1;
}
return 0;
}
//
// Write a block to the PATA hard drive
//
@ -292,6 +339,7 @@ short pata_write(long lba, const unsigned char * buffer, short size) {
}
*PATA_HEAD = ((lba >> 24) & 0x07) | 0xe0; // Upper 3 bits of LBA, Drive 0, LBA mode.
if (pata_wait_ready_not_busy()) {
return DEV_TIMEOUT;
}
@ -299,7 +347,7 @@ short pata_write(long lba, const unsigned char * buffer, short size) {
*PATA_SECT_CNT = 1; // Read one sector (make this an option?)
*PATA_SECT_SRT = lba & 0xff; // Set the rest of the LBA
*PATA_CLDR_LO = (lba >> 8) & 0xff;
*PATA_CLDR_LO = (lba >> 16) & 0xff;
*PATA_CLDR_HI = (lba >> 16) & 0xff;
*PATA_CMD_STAT = PATA_CMD_WRITE_SECTOR; // Issue the WRITE command
@ -336,8 +384,6 @@ short pata_write(long lba, const unsigned char * buffer, short size) {
return -1;
}
TRACE("PATA WRITE COMPLETE");
return size;
}

View file

@ -302,6 +302,22 @@ void text_set_color(short screen, short foreground, short background) {
}
}
/*
* Get the foreground and background color for printing
*
* Inputs:
* screen = the screen number 0 for channel A, 1 for channel B
* foreground = pointer to the foreground color number
* background = pointer to the background color number
*/
void text_get_color(short screen, short * foreground, short * background) {
if (screen < MAX_TEXT_CHANNELS) {
p_text_channel chan = &text_channel[screen];
*foreground = (chan->current_color >> 4) & 0x0f;
*background = chan->current_color & 0x0f;
}
}
/*
* Clear the screen of data
*

View file

@ -73,6 +73,16 @@ extern void text_put_raw(short screen, char c);
*/
extern void text_set_color(short screen, short foreground, short background);
/*
* Get the foreground and background color for printing
*
* Inputs:
* screen = the screen number 0 for channel A, 1 for channel B
* foreground = pointer to the foreground color number
* background = pointer to the background color number
*/
extern void text_get_color(short screen, short * foreground, short * background);
/*
* Clear the screen of data
*

View file

@ -344,8 +344,8 @@ int main(int argc, char * argv[]) {
initialize();
// const char * welcome = "\x1B[2J\x1B[HFoenix/MCP Command Line Utility... online.\x1B[;2HType \"HELP\" or \"?\" for help.\n";
// sys_chan_write(0, welcome, strlen(welcome));
const char * welcome = "\x1B[2J\x1B[;1HFoenix/MCP Command Line Utility... online."; // "\x1B[;2HType \"HELP\" or \"?\" for help.\n";
sys_chan_write(0, welcome, strlen(welcome));
cli_repl(0);

File diff suppressed because it is too large Load diff

10764
src/mapfile

File diff suppressed because it is too large Load diff

View file

@ -147,3 +147,50 @@ unsigned char i_to_bcd(unsigned short n) {
return tens << 4 | ones;
}
}
/*
* Print a nice dump of a byte buffer to the channel
*
* Inputs:
* channel = the number of the channel
* buffer = the byte buffer to print
* size = the number of bytes to print
*/
void dump_buffer(short channel, unsigned char * buffer, short size) {
short i, j, ascii_idx;
char ascii_buffer[17];
unsigned char c;
for (j = 0; j < 17; j++) {
ascii_buffer[j] = 0;
}
for (i = 0; i < size; i++) {
c = buffer[i];
if (i % 16 == 0) {
print(channel, " ");
print(channel, ascii_buffer);
print(channel, "\n");
for (j = 0; j < 17; j++) {
ascii_buffer[j] = 0;
}
ascii_idx = 0;
}
if (isgraph(c)) {
ascii_buffer[ascii_idx++] = c;
} else {
ascii_buffer[ascii_idx++] = '.';
}
print_hex_8(channel, c);
print(channel, " ");
}
print(channel, " ");
print(channel, ascii_buffer);
print(channel, "\n");
}

View file

@ -72,4 +72,14 @@ extern unsigned short bcd_to_i(unsigned char bcd);
*/
extern unsigned char i_to_bcd(unsigned short n);
/*
* Print a nice dump of a byte buffer to the channel
*
* Inputs:
* channel = the number of the channel
* buffer = the byte buffer to print
* size = the number of bytes to print
*/
extern void dump_buffer(short channel, unsigned char * buffer, short size);
#endif