PGX Loader and Interrupt Update

PGX loader is working, updated interrupt code to support keyboard interrupts (currently using Mo keyboard)
This commit is contained in:
Peter Weingartner 2021-09-27 17:37:36 -04:00
parent 6beafc1c7e
commit ee4d8db4fa
19 changed files with 6432 additions and 6086 deletions

View file

@ -0,0 +1,15 @@
# Sample: HelloPGX #
One of the simple executable formats that the FoenixMCP supports is the PGX format inherited from the original Foenix stock kernel. This assembly demo uses the VASM assembler to create a simple PGX file that prints "Hello, world."
## Building ##
Make sure that the VASM binaries are in your executable path and then use the `build.bat` file to create the PGX file.
## PGX Format ##
PGX is a very simple binary file format. It is designed to load a single segment of code or data to a single block of memory. A PGX file begins with a small header (eight bytes), and the remainder of the file is the data to load:
* The first three bytes are the format signature: the ASCII characters "PGX".
* The fourth byte is the version and target CPU code. Currently, only format 0 is used. There are two CPU codes supported: 1 = 65816, 2 = 68000.
* The next four bytes are the target address for loading the data (i.e. the address of the first byte of the data). The address is to be written in the 32-bit integer format native for the target processor. For the 65816, the address will be in little-endian format. For the 68000 processors, the address will be in big-endian format.

View file

@ -0,0 +1,2 @@
@echo off
vasmm68k_mot -Fbin -L hello.lst -o hello.pgx hello.s

View file

@ -0,0 +1,57 @@
F00:0001 ;;;
F00:0002 ;;; Sample PGX Program
F00:0003 ;;;
F00:0004
F00:0005 org $010000
F00:0006
F00:0007 dc.b "PGX", $02
S01:00010000: 50 47 58
S01:00010003: 02
F00:0008 dc.l _start
S01:00010004: 00 01 00 08
F00:0009
F00:0010 _start: move.l #_greet_end-_greet+1,d3 ; Length of the message
S01:00010008: 76 0E
F00:0011 move.l #_greet,d2 ; Pointer to the message
S01:0001000A: 24 3C 00 01 00 18
F00:0012 clr.l d1 ; Write to channel #0 (main screen)
S01:00010010: 72 00
F00:0013 move.l #$14,d0 ; sys_chan_write_b
S01:00010012: 70 14
F00:0014 trap #15 ; Call it
S01:00010014: 4E 4F
F00:0015
F00:0016 _lock: bra _lock
S01:00010016: 60 FE
F00:0017
F00:0018 _greet: dc.b "Hello, world!"
S01:00010018: 48 65 6C 6C 6F 2C 20 77 6F 72 6C 64 21
F00:0019 _greet_end: dc.b 0
S01:00010025: 00
F00:0020
Sections:
S01 seg10000
Sources:
F00 hello.s
Symbols:
_lock EXPR(65558=0x10016) ABS
_greet EXPR(65560=0x10018) ABS
_greet_end EXPR(65573=0x10025) ABS
_start EXPR(65544=0x10008) ABS
_MOVEMBYTES EXPR(0=0x0) INTERNAL
MOVEMSIZE EXPR(0=0x0) INTERNAL
_MOVEMREGS EXPR(0=0x0) INTERNAL
__LINE__ EXPR(20=0x14) INTERNAL
__FO EXPR(0=0x0) INTERNAL
__RS EXPR(0=0x0) INTERNAL
REPTN EXPR(-1=0xffffffff) INTERNAL
__VASM EXPR(1=0x1) INTERNAL
__UNIXFS EXPR(0=0x0) INTERNAL
There have been no errors.

BIN
samples/HelloPGX/hello.pgx Normal file

Binary file not shown.

19
samples/HelloPGX/hello.s Normal file
View file

@ -0,0 +1,19 @@
;;;
;;; Sample PGX Program
;;;
org $010000
dc.b "PGX", $02
dc.l _start
_start: move.l #_greet_end-_greet+1,d3 ; Length of the message
move.l #_greet,d2 ; Pointer to the message
clr.l d1 ; Write to channel #0 (main screen)
move.l #$14,d0 ; sys_chan_write_b
trap #15 ; Call it
_lock: bra _lock
_greet: dc.b "Hello, world!"
_greet_end: dc.b 0

View file

@ -4,22 +4,12 @@
#include "syscalls.h"
#include "log.h"
#include "simpleio.h"
#include "cli.h"
#include "cli/dos_cmds.h"
#include "dev/block.h"
#include "dev/fsys.h"
#include "fatfs/ff.h"
/*
* Fetch and display the MBR for the specified device:
*
* Inputs:
* drive = "@S" for SDC, "@H" for hard drive
*/
short cmd_dump_mbr(short screen, char * drive) {
return 0;
}
short cmd_dir(short screen, int argc, char * argv[]) {
t_file_info my_file;
char * path = "";
@ -84,6 +74,7 @@ short cmd_type(short screen, int argc, char * argv[]) {
}
} else {
log(LOG_ERROR, "Usage: TYPE <path>");
return -1;
}
}
@ -94,7 +85,13 @@ short cmd_type(short screen, int argc, char * argv[]) {
short cmd_load(short screen, int argc, char * argv[]) {
if (argc > 1) {
long start = 0;
short result = fsys_load(argv[1], 0x30000, &start);
long destination = 0;
if (argc > 2) {
destination = cli_eval_number(argv[2]);
}
short result = fsys_load(argv[1], destination, &start);
if (result == 0) {
if (start != 0) {
log(LOG_INFO, "Loaded file with a start adddress.");
@ -103,10 +100,12 @@ short cmd_load(short screen, int argc, char * argv[]) {
}
} else {
log_num(LOG_ERROR, "Unable to open file: ", result);
return -1;
}
return result;
} else {
log(LOG_ERROR, "Usage: LOAD <path>");
log(LOG_ERROR, "Usage: LOAD <path> [<destination>]");
return -1;
}
}

View file

@ -5,14 +5,6 @@
#ifndef __DOS_CMDS_H
#define __DOS_CMDS_H
/*
* Fetch and display the MBR for the specified device:
*
* Inputs:
* drive = "@S" for SDC, "@H" for hard drive
*/
extern short cmd_dump_mbr(char * drive);
/*
* List the directory at the given path
*/

View file

@ -35,7 +35,7 @@ short con_write_b(p_channel chan, uint8_t b) {
short con_read_b(p_channel chan) {
char c;
do {
c = kbd_getc_poll();
c = kbdmo_getc();
} while (c == 0);
// Echo the character to the screen

View file

@ -7,12 +7,14 @@
*/
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include "log.h"
#include "syscalls.h"
#include "fsys.h"
#include "fatfs/ff.h"
#include "dev/channel.h"
#include "simpleio.h"
#include "errors.h"
#define MAX_DRIVES 8 /* Maximum number of drives */
@ -612,6 +614,87 @@ unsigned short atoi_hex(char * hex) {
return (atoi_hex_1(hex[0]) << 4 | atoi_hex_1(hex[1]));
}
/*
* Loader for the PGX binary file format
*
* Inputs:
* path = the path to the file to load
* destination = the destination address (ignored for PGX)
* start = pointer to the long variable to fill with the starting address
* (0 if not an executable, any other number if file is executable
* with a known starting address)
*
* Returns:
* 0 on success, negative number on error
*/
short fsys_pgx_loader(short chan, long destination, long * start) {
const char signature[] = "PGX\x02";
unsigned char * chunk = 0;
unsigned char * dest = 0;
long file_idx = 0;
long address = 0;
short result = 0;
TRACE("fsys_pgx_loader");
chunk = malloc(DEFAULT_CHUNK_SIZE);
if (chunk == 0) {
result = ERR_OUT_OF_MEMORY;
} else {
/* We have our buffer... start reading chunks into it */
short n = 1;
while (result == 0) {
/* Try to read a chunk of data */
n = chan_read(chan, chunk, DEFAULT_CHUNK_SIZE);
if (n > 0) {
short i;
/* Loop through all the bytes of the chunk that we read */
for (i = 0; i < n; i++, file_idx++) {
if (file_idx < 4) {
/* Check that the first four bytes match the signature for this CPU */
if (chunk[i] != signature[i]) {
/* If signature does not match, quit */
result = ERR_BAD_BINARY;
break;
}
} else if (file_idx < 8) {
/* Parse the next four bytes as the target address */
address = (address << 8) + chunk[i];
} else {
/* Treat the remaining bytes as data */
if (file_idx == 8) {
/* For the first data byte, set our destination pointer */
dest = (unsigned char *)address;
}
/* Store the data in the destination address */
*dest++ = chunk[i];
}
}
} else if (n < 0) {
/* We got an error while reading... pass it to the caller */
result = n;
break;
} else if (n == 0) {
break;
}
}
}
/* Start address is the first byte of the data */
*start = address;
if (chunk != 0) {
free(chunk);
}
return result;
}
/*
* Loader for the Motorola SREC format
*
@ -786,21 +869,23 @@ short fsys_load(const char * path, long destination, long * start) {
extension[i] = 0;
}
/* Find the extension */
char * point = strrchr(path, '.');
if (point != 0) {
point++;
for (i = 0; i < MAX_EXT; i++) {
char c = *point++;
if (c) {
extension[i] = toupper(c);
} else {
break;
if (destination == 0) {
/* Find the extension */
char * point = strrchr(path, '.');
if (point != 0) {
point++;
for (i = 0; i < MAX_EXT; i++) {
char c = *point++;
if (c) {
extension[i] = toupper(c);
} else {
break;
}
}
}
}
TRACE("fsys_load: ext");
log2(LOG_VERBOSE, "fsys_load ext: ", extension);
if (extension[0] == 0) {
if (destination != 0) {
@ -851,9 +936,15 @@ short fsys_load(const char * path, long destination, long * start) {
/* If it opened correctly, load the file */
short result = loader(chan, destination, start);
fsys_close(chan);
if (result != 0) {
log_num(LOG_ERROR, "Could not load file: ", result);
}
return result;
} else {
/* File open returned an error... pass it along */
log_num(LOG_ERROR, "Could not open file: ", chan);
return chan;
}
}
@ -877,7 +968,7 @@ short fsys_register_loader(const char * extension, p_file_loader loader) {
for (i = 0; i < MAX_LOADERS; i++) {
if (g_file_loader[i].status == 0) {
g_file_loader[i].status = 1; /* Claim this loader record */
g_file_loader[j].loader = loader; /* Set the loader routine */
g_file_loader[i].loader = loader; /* Set the loader routine */
for (j = 0; j <= MAX_EXT; j++) { /* Clear out the extension */
g_file_loader[i].extension[j] = 0;
}
@ -934,8 +1025,9 @@ short fsys_init() {
}
}
/* Register the SREC loader */
/* Register the built-in binary file loaders */
fsys_register_loader("PRS", fsys_srec_loader);
fsys_register_loader("PGX", fsys_pgx_loader);
/* Register the channel driver for files. */

View file

@ -215,13 +215,13 @@ short kbdmo_init() {
kbdmo_flush_out();
/* Clear out any pending interrupt */
// int_clear(INT_KBD_A2560K);
//
// /* Register a handler for the keyboard */
// int_register(INT_KBD_A2560K, kbdmo_handle_irq);
//
// /* Enable the interrupt for the keyboard */
// int_enable(INT_KBD_A2560K);
int_clear(INT_KBD_A2560K);
/* Register a handler for the keyboard */
int_register(INT_KBD_A2560K, kbdmo_handle_irq);
/* Enable the interrupt for the keyboard */
int_enable(INT_KBD_A2560K);
return 0;
}
@ -317,7 +317,7 @@ void kbdmo_handle_irq() {
*/
while ((*KBD_MO_STAT & 0x00ff) != 0) {
/* Get a scan code from the input buffer */
unsigned char scan_code = *KBD_MO_DATA;
unsigned short scan_code = *KBD_MO_DATA;
if ((scan_code & 0x7fff) != 0) {
/* TODO: beep if the input was full or the ring buffer is full */

View file

@ -40,4 +40,6 @@ extern char kbdmo_getc_poll();
*/
extern unsigned short kbdmo_get_scancode_poll();
extern void kbdmo_handle_irq();
#endif

View file

@ -469,6 +469,9 @@ void kbd_handle_irq() {
unsigned char scan_code = *data;
unsigned char translated_code;
/* Clear the pending flag */
int_clear(INT_KBD_PS2);
if (scan_code) {
// Make sure the scan code isn't 0 or 128, which are invalid make/break codes
if ((scan_code != 0) && (scan_code != 0x80)) {
@ -763,14 +766,14 @@ short ps2_init() {
ps2_flush_out();
// // Controller selftest...
// if (ps2_controller_cmd(PS2_CTRL_SELFTEST) != PS2_RESP_OK) {
// ; // return PS2_FAIL_SELFTEST;
// }
if (ps2_controller_cmd(PS2_CTRL_SELFTEST) != PS2_RESP_OK) {
; // return PS2_FAIL_SELFTEST;
}
//
// // Keyboard test
// if (ps2_controller_cmd(PS2_CTRL_KBDTEST) != 0) {
// ; // return PS2_FAIL_KBDTEST;
// }
if (ps2_controller_cmd(PS2_CTRL_KBDTEST) != 0) {
; // return PS2_FAIL_KBDTEST;
}
// Set scancode translation to set1, enable interrupts on mouse and keyboard
ps2_controller_cmd_param(PS2_CTRL_WRITECMD, 0x43);

View file

@ -96,7 +96,7 @@ void initialize() {
text_init(); // Initialize the text channels
DEBUG("Foenix/MCP starting up...");
log_setlevel(LOG_ERROR);
log_setlevel(LOG_VERBOSE);
/* Initialize the interrupt system */
int_init();
@ -146,11 +146,11 @@ void initialize() {
// At this point, we should be able to call into to console to print to the screens
if (res = ps2_init()) {
print_error(0, "FAILED: PS/2 keyboard initialization", res);
} else {
DEBUG("PS/2 keyboard initialized.");
}
// if (res = ps2_init()) {
// print_error(0, "FAILED: PS/2 keyboard initialization", res);
// } else {
// DEBUG("PS/2 keyboard initialized.");
// }
if (res = kbdmo_init()) {
print_error(0, "FAILED: A2560K built-in keyboard initialization", res);
@ -171,7 +171,7 @@ void initialize() {
}
/* Enable all interrupts */
// int_enable_all();
int_enable_all();
}
// void try_mo_scancodes(short screen) {
@ -259,6 +259,18 @@ void int_sof_a() {
int_clear(SOF_A_INT00);
}
/*
* Interrupt handler for Channel A's Start of Frame
*/
void change_led() {
g_sof_counter++;
long counter_mod = g_sof_counter % 2;
*RGB_LED_L = 0x0000;
*RGB_LED_H = 0xFF00;
}
void try_format(short screen, char * path) {
FATFS fs; /* Filesystem object */
FIL fil; /* File object */
@ -368,6 +380,14 @@ int main(int argc, char * argv[]) {
print(CDEV_CONSOLE, "Text Channel A\n");
print(CDEV_EVID, "Text Channel B\n");
print(CDEV_CONSOLE, "MASK_GRP1: ");
print_hex_16(CDEV_CONSOLE, *MASK_GRP1);
print(CDEV_CONSOLE, "\n");
print(CDEV_CONSOLE, "MASK_PEND1: ");
print_hex_16(CDEV_CONSOLE, *PENDING_GRP1);
print(CDEV_CONSOLE, "\n");
// uart_test_send(0);
/* Register a handler for the SOF interrupt and enable it */

File diff suppressed because it is too large Load diff

View file

@ -5,7 +5,7 @@
#ifndef __ERRORS_H
#define __ERRORS_H
#define MAX_ERROR_NUMBER 12 // Largest (absolute value) of the error number
#define MAX_ERROR_NUMBER 15 // Largest (absolute value) of the error number
#define ERR_GENERAL -1 // A general error condition
#define DEV_ERR_BADDEV -2 // Device number is bad (too big or no device assigned)
@ -21,5 +21,6 @@
#define ERR_BAD_HANDLE -12 // The handle passed was not valid
#define ERR_BAD_EXTENSION -13 // The path to load did not have an extension that matched registered loaders
#define ERR_OUT_OF_MEMORY -14 // Unable to allocate more memory
#define ERR_BAD_BINARY -15 // Bad binary file format... i.e. binary format does not match expectations
#endif

View file

@ -98,6 +98,7 @@ typedef void (*p_int_handler)();
#define EXT_OPL3_INT25 0x0020 // External OPL3 Interrupt
#define RESERVED5 0x0040 // No interrupt - Reserved
#define RESERVED6 0x0080 // No interrupt - Reserved
#define BEATRIX_INT28 0x0100 // Beatrix Interrupt 0
#define BEATRIX_INT29 0x0200 // Beatrix Interrupt 1
#define BEATRIX_INT2A 0x0400 // Beatrix Interrupt 2

View file

@ -138,22 +138,27 @@ autovec1: movem.l d0-d7/a0-a6,-(a7)
movem.l (a7)+,d0-d7/a0-a6
rte
;
; Autovector #1: Used by VICKY III Channel A interrupts
;
autovec2: movem.l d0-d7/a0-a6,-(a7)
jsr _int_vicky_channel_a ; Call the dispatcher for Channel A interrupts
movem.l (a7)+,d0-d7/a0-a6
rte
;
; Interrupt Vector 0x10 -- SuperIO Keyboard
;
interrupt_x10:
movem.l d0-d7/a0-a6,-(a7) ; Save all the registers
;lea _g_int_handler,a0 ; Look in the interrupt handler table
;move.w #($10<<2),d0 ; Offset to interrupt #16
;movea.l (0,a0,d0),a1 ; Get the address of the handler
;beq done_intx10 ; If there isn't one, just return
; moveq #0,d2
; moveq #'!',d3
; moveq #$14,d1
; trap #13
; move.l #$00C60001,a0
; move.l #$00C60000,a1
; move.b (a0),d0
; addq.b #1,d0
; move.b d0,(a1)
jsr _kbd_handle_irq ; If there is, call it.
; jsr _kbd_handle_irq ; If there is, call it.
done_intx10 movem.l (a7)+,d0-d7/a0-a6 ; Restore the registers
rte
@ -168,29 +173,18 @@ interrupt_x11:
; ; movea.l (0,a0,d0),a1 ; Get the address of the handler
; ; beq done_intx10 ; If there isn't one, just return
;
; moveq #0,d2
; moveq #'@',d3
; moveq #$14,d1
; trap #13
;
; ; jsr (a1) ; If there is, call it.
; moveq #0,d2
; moveq #'!',d3
; moveq #$14,d1
; trap #13
move.l #$00C00102,a0 ; Clear the pending flag
move.w (a0),d0
andi.w #$0002,d0
move.w d0,(a0)
jsr _kbdmo_handle_irq
done_intx11 movem.l (a7)+,d0-d7/a0-a6 ; Restore the registers
rte
;
; Autovector #1: Used by VICKY III Channel A interrupts
;
autovec2: movem.l d0-d7/a0-a6,-(a7)
jsr _int_vicky_channel_a ; Call the dispatcher for Channel A interrupts
movem.l (a7)+,d0-d7/a0-a6
rte
;
; Unimplemented Exception Handler -- just return
;

File diff suppressed because it is too large Load diff

View file

@ -7,6 +7,16 @@
*** Core system calls
***/
/*
* Stop running the current user program
*
* Inputs:
* result = the result code to return to the kernel
*/
void sys_exit(short result) {
syscall(KFN_EXIT, result);
}
/*
* Enable all interrupts
*