Beta 1 for F256!

This commit is contained in:
Scott Duensing 2024-02-05 19:47:10 -06:00
parent 52c03bb42c
commit 25f8ccc72d
18 changed files with 268 additions and 69 deletions

View file

@ -28,6 +28,7 @@
#include "common.h"
void portAttributeSet(byte attribute);
uint8_t portByteGet(uint32_t address);
void portByteSet(uint32_t address, uint8_t value);
char portCharGet(void);

View file

@ -40,6 +40,7 @@ typedef struct stateS {
uint8_t operandCount;
uint16_t operands[8];
char alphabetTable[78];
uint16_t checksum;
char statusBar[256];
byte statusBarLen;
byte currentWindow;
@ -48,6 +49,7 @@ typedef struct stateS {
byte savedY;
bool outputting;
bool redirecting;
byte linesOut;
#ifdef DEBUGGING
char *opcodesName[256];
char *extOpcodesName[30];

View file

@ -118,6 +118,7 @@
#define storyHXTrueDefaultBackgroundColor() portWordGet(storyHeaderExtensionTableAddress() + 12)
void storyChecksumCalculate(void);
uint32_t storyLength(void);
void storySetup(byte width, byte height);

View file

@ -21,8 +21,8 @@
*/
#ifndef TEXT_H
#define TEXT_H
#ifndef TEXT_ZIP_H
#define TEXT_ZIP_H
#include "common.h"
@ -33,6 +33,12 @@
#define STREAM_OUTPUT_MEMORY 3
#define STREAM_OUTPUT_SCRIPT 4
#define TEXT_ATTR_NORMAL 0
#define TEXT_ATTR_REVERSE 1
#define TEXT_ATTR_BOLD 2
#define TEXT_ATTR_EMPHASIS 4
#define TEXT_ATTR_FIXED_FONT 8
void textCharPrint(char c);
void textInput(uint32_t ramAddr, uint8_t length);
@ -43,4 +49,4 @@ void textStringPrint(char *s);
void textTimePrint(uint16_t hours, uint16_t minutes);
#endif // TEXT_H
#endif // TEXT_ZIP_H

View file

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.12)
project(zip LANGUAGES C)
project(dos-like-zip LANGUAGES C)
find_package(SDL2 REQUIRED)
@ -30,8 +30,6 @@ set(HEADERS
variable.h
window.h
zscii.h
# czech.z3.h
zork1.h
)
list(TRANSFORM HEADERS PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/../../include/")

View file

@ -30,9 +30,7 @@
#include "story.h"
#include "state.h"
#include "interpreter.h"
#include "zork1.h"
//#include "czech.z3.h"
#include "text.h"
#pragma push_macro("bool")
#undef bool
@ -41,8 +39,38 @@
#pragma pop_macro("bool")
// The F256 has 512k of RAM. We use everything except the lower 64k.
static uint8_t _RAM[1024 * (512 - 64)];
static char *_storyFile = NULL;
static uint8_t *_RAM = NULL;
static uint8_t _attr = 7;
void portAttributeSet(byte attribute) {
switch (attribute) {
case TEXT_ATTR_NORMAL:
textbackground(1);
textcolor(7);
_attr = (1 << 4) + 7;
break;
case TEXT_ATTR_REVERSE:
textbackground(7);
textcolor(1);
_attr = (7 << 4) + 1;
break;
case TEXT_ATTR_BOLD:
textbackground(1);
textcolor(15);
_attr = (1 << 4) + 15;
break;
case TEXT_ATTR_EMPHASIS:
textbackground(1);
textcolor(14);
_attr = (1 << 4) + 14;
break;
}
}
uint8_t portByteGet(uint32_t address) {
@ -85,13 +113,17 @@ void portCharGetPos(byte *x, byte *y) {
void portCharPrint(char c) {
char ch[2] = { 0, 0 };
char ch[2] = { 0, 0 };
uint16_t *p;
uint16_t v = (_attr << 8) + ' ';
byte x;
if ((wherex() >= screenwidth()) || (c == '\n')) {
gotoxy(0, wherey() + 1);
while (wherey() >= screenheight()) {
memmove(((uint16_t*)screenbuffer()), ((uint16_t*)screenbuffer()) + screenwidth(), screenwidth() * (screenheight() - 1) * sizeof(uint16_t));
memset(((uint16_t*)screenbuffer()) + screenwidth() * (screenheight() - 1), 0, screenwidth() * sizeof(uint16_t));
p = (uint16_t *)screenbuffer() + (screenwidth() * (screenheight() - 1));
for (x=0; x<screenwidth(); x++) *p++ = v;
gotoxy(0, wherey() - 1);
}
return;
@ -177,14 +209,41 @@ uint16_t portRandomGet(int16_t range) {
// If range is zero, randomize with "best" random seed.
// If range is negative, use the positive value to seed.
return 42;
if (range <= 0) {
srandom(range < 0 ? -range : time(NULL));
return 0;
}
return (random() % range) + 1;
}
void portStoryLoad(void) {
// For now, we just copy an embedded Zork 1 into RAM.
memcpy(_RAM, zork1, zork1_len);
//memcpy(_RAM, czech_z3, czech_z3_len);
FILE *in;
uint32_t length;
in = fopen(_storyFile, "rb");
if (!in) portDie("Unable to open %s!\n", _storyFile);
fseek(in, 0, SEEK_END);
length = ftell(in);
fseek(in, 0, SEEK_SET);
_RAM = (byte *)malloc(length);
if (!_RAM) {
fclose(in);
portDie("Unable to allocate %u bytes!\n", length);
}
if (fread(_RAM, length, 1, in) != 1) {
free(_RAM);
fclose(in);
portDie("Unable to read %s!\n", _storyFile);
}
fclose(in);
storyChecksumCalculate();
}
@ -201,12 +260,16 @@ void portWordSet(uint32_t address, uint16_t value) {
int main(int argc, char *argv[]) {
(void)argc;
(void)argv;
if (argc != 2) portDie("Usage: %s [storyfile]\n", argv[0]);
_storyFile = argv[1];
setvideomode(videomode_80x25_9x16);
curson();
textbackground(1);
textcolor(7);
clrscr();
gotoxy(0, screenheight() - 1);
stateReset();
portStoryLoad();
@ -214,5 +277,7 @@ int main(int argc, char *argv[]) {
storySetup(80, 25);
interpreterRun();
free(_RAM);
return 0;
}

View file

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.12)
project(zip LANGUAGES C)
project(f256-zip LANGUAGES C)
set(HEADERS
common.h
@ -64,4 +64,8 @@ add_executable(${CMAKE_PROJECT_NAME}
f256zip.c
)
target_include_directories(${CMAKE_PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../../include)
target_include_directories(${CMAKE_PROJECT_NAME} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../../include
${CMAKE_CURRENT_SOURCE_DIR}/../../../f256/include
${CMAKE_CURRENT_SOURCE_DIR}/../../../f256/f256lib
)

View file

@ -33,7 +33,7 @@ PATH=${LLVM}/bin:${PATH}
echo "__f256_start = ${START};" > ${SETTINGS}
CLANG="mos-f256k-clang -I../../../include -I${F256}/include -I${F256}/f256lib -Os"
CLANG="mos-f256k-clang -I${F256}/include -I../../../include -I${F256}/f256lib -Os"
[[ -d .builddir ]] && rm -rf .builddir
mkdir -p .builddir

View file

@ -42,12 +42,36 @@
#include "memory.h"
#include "state.h"
#include "interpreter.h"
#include "lib.h"
#include "../../include/text.h"
#define BASE_ADDRESS 0x10000
static char *_saveName = 0;
void portAttributeSet(byte attribute) {
switch (attribute) {
case TEXT_ATTR_NORMAL:
textSetColor(7, 1);
break;
case TEXT_ATTR_REVERSE:
textSetColor(1, 7);
break;
case TEXT_ATTR_BOLD:
textSetColor(15, 1);
break;
case TEXT_ATTR_EMPHASIS:
textSetColor(14, 1);
break;
}
}
uint8_t portByteGet(uint32_t address) {
return FAR_PEEK(BASE_ADDRESS + address);
}
@ -97,7 +121,7 @@ bool portFileRestore(void) {
uint32_t i;
byte b;
in = fopen("save.dat", "rb");
in = fopen(_saveName, "rb");
if (in) {
ok = true;
@ -128,7 +152,7 @@ bool portFileSave(void) {
uint32_t i;
byte b;
out = fopen("save.dat", "wb");
out = fopen(_saveName, "wb");
if (out) {
ok = true;
@ -154,7 +178,7 @@ bool portFileSave(void) {
char portCharGet(void) {
#if 1
#if 0
static char playback[] = "open mailbox\ntake leaflet\nread leaflet\ndrop leaflet\n";
static uint32_t pointer = 0;
@ -183,10 +207,13 @@ uint16_t portRandomGet(int16_t range) {
void portStoryLoad(void) {
// On the F256, the story is loaded into RAM along with the ZIP.
// ***TODO*** This likely breaks the "restart" command.
// Later, we probably want to see if the user has a memory expansion
// installed. If they do, we can use it and then use the lower memory
// for graphics and sound.
storyChecksumCalculate();
}
@ -201,15 +228,54 @@ void portWordSet(uint32_t address, uint16_t value) {
int main(void) {
byte c;
byte colors[16][3] = {
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0xaa },
{ 0x00, 0xaa, 0x00 },
{ 0x00, 0xaa, 0xaa },
{ 0xaa, 0x00, 0x00 },
{ 0xaa, 0x00, 0xaa },
{ 0xaa, 0x55, 0x00 },
{ 0xaa, 0xaa, 0xaa },
{ 0x55, 0x55, 0x55 },
{ 0x55, 0x55, 0xff },
{ 0x55, 0xff, 0x55 },
{ 0x55, 0xff, 0xff },
{ 0xff, 0x55, 0x55 },
{ 0xff, 0x55, 0xff },
{ 0xff, 0xff, 0x55 },
{ 0xff, 0xff, 0xff }
};
_saveName = "zork1.sav";
f256Init();
textSetCursor(199);
// Load EGA palette into text CLUT.
for (c=0; c<16; c++) {
textDefineForegroundColor(c, colors[c][0], colors[c][1], colors[c][2]);
textDefineBackgroundColor(c, colors[c][0], colors[c][1], colors[c][2]);
}
textEnableBackgroundColors(true);
textSetColor(15, 0);
textPrint("Welcome to MUDDLE Beta 1, Another Z-Machine!\n\n");
textSetColor(7, 0);
textPrint("Copyright 2024 Scott Duensing, All Rights Reserved.\n");
textPrint("Kangaroo Punch Studios https://kangaroopunch.com\n\n\n");
textSetColor(8, 0);
textPrint("Thinking...");
stateReset();
portStoryLoad();
opcodesSetup();
storySetup(80, 30);
textSetColor(7, 1);
textClear();
textSetCursor(199);
interpreterRun();
return 0;

View file

@ -64,7 +64,7 @@ void interpreterDoReturn(uint16_t r) {
if (__state.bp == 0) portDie(MSG_INT_STACK_UNDERFLOW);
#ifdef DEBUGGING
#ifdef DEBUGGINGx
printf("Returning: initial pc=%X, bp=%u, sp=%u\n", (unsigned int)__state.pc, __state.bp, __state.sp);
#endif
@ -82,7 +82,7 @@ void interpreterDoReturn(uint16_t r) {
// Pop the result storage location.
storeId = (uint8_t)__state.stack[--__state.sp];
#ifdef DEBUGGING
#ifdef DEBUGGINGx
printf("Returning: new pc=%X, bp=%u, sp=%u\n", (unsigned int)__state.pc, __state.bp, __state.sp);
#endif
@ -136,6 +136,10 @@ void interpreterRun(void) {
opcodeT op;
bool eight;
__state.savedX = 1;
__state.savedY = storyScreenHeightLines();
portCharSetPos(__state.savedX, __state.savedY);
while (__state.quit == 0) {
opcode = ZPEEK(__state.pc++);
extended = ((opcode == 190) && (storyVersion() >= 5)) ? true : false;
@ -183,7 +187,7 @@ void interpreterRun(void) {
if (op == 0) portDie(MSG_INT_UNIMPLEMENTED_OPCODE, extended ? "ext" : "", opcode);
#ifdef DEBUGGING
#ifdef DEBUGGINGx
printf("ins=%u pc=%X sp=%u bp=%u %sopcode=%u ('%s') [",
__state.instructionsRun,
(unsigned int)__state.pc,
@ -199,6 +203,7 @@ void interpreterRun(void) {
printf("%X", (unsigned int)__state.operands[i]);
}
printf("]\n");
fflush(stdout);
if (__state.instructionsRun == 261) {
printf("\n*** BREAKING ***\n");
@ -247,6 +252,7 @@ void interpreterTokenizeInput(void) {
#ifdef DEBUGGING
printf("Max parse: %u\n", parseLen);
printf("Parse Input: [");
#endif
if (parseLen == 0) portDie(MSG_INT_PARSE_BUFFER_TOO_SMALL);
@ -260,7 +266,9 @@ void interpreterTokenizeInput(void) {
while (1) {
isSep = false;
ch = ZPEEK(ptr);
#ifdef DEBUGGING
printf("%c", ch);
#endif
if ((ch == ' ') || (ch == 0)) {
isSep = true;
} else {
@ -358,7 +366,9 @@ void interpreterTokenizeInput(void) {
} // while
#ifdef DEBUGGING
printf("]\n");
printf("Tokenized %u tokens\n", (unsigned int)numToks);
fflush(stdout);
#endif
ZPOKE(__state.operands[1] + 1, numToks);

View file

@ -46,7 +46,7 @@ void opcodes_call(void) {
} else {
routine = memoryUnpackAddress(__state.operands[0], MEMORY_ROUTINE);
numLocals = ZPEEK(routine++);
#ifdef DEBUGGING
#ifdef DEBUGGINGx
printf("op0=%u routine=%X, numLocals=%d\n", __state.operands[0], (unsigned int)routine, numLocals);
#endif
if (numLocals > 15) portDie(MSG_OP_CALL_TOO_MANY_LOCALS, numLocals);

View file

@ -68,11 +68,15 @@ void opcodes_read(void) {
ZPOKE(i, ch);
} else if ((ch == '\n') || (ch == '\r') || (ch == 0)) {
// End of line, end of input.
ch = 0;
ZPOKE(i, ch);
ZPOKE(i, 0);
break;
}
}
i++;
for (; i<input+inputLen; i++) ZPOKE(i, 0);
// Reset [MORE] counter.
__state.linesOut = 0;
interpreterTokenizeInput();
}

View file

@ -26,8 +26,8 @@
#include "variable.h"
#include "portme.h"
#include "story.h"
#include "memory.h"
#include "interpreter.h"
#include "memory.h"
void opcodes_nop(void) {
@ -47,26 +47,10 @@ void opcodes_piracy(void) {
void opcodes_random(void) {
variableStore((__state.pc++), portRandomGet((int16_t)__state.operands[0]));
variableStore(ZPEEK(__state.pc++), portRandomGet((int16_t)__state.operands[0]));
}
void opcodes_verify(void) {
/*
uint16_t checksum = 0;
uint32_t i;
for (i=64; i<storyLength(); i++) checksum += ZPEEK(i);
checksum %= 0x10000;
#ifdef DEBUGGING
printf("\n\nChecksum = %u Header = %d\n\n", checksum, storyChecksum());
#endif
interpreterDoBranch(checksum == storyChecksum() ? 1 : 0);
*/
// We lie. Everything passes.
interpreterDoBranch(1);
interpreterDoBranch(__state.checksum == storyChecksum() ? 1 : 0);
}

View file

@ -37,23 +37,26 @@ void opcodes_save(void) {
void opcodes_restart(void) {
byte width = ZPEEK(STORY_SCREEN_WIDTH_CHARACTERS);
byte height = ZPEEK(STORY_SCREEN_HEIGHT_LINES);
byte width = ZPEEK(STORY_SCREEN_WIDTH_CHARACTERS);
byte height = ZPEEK(STORY_SCREEN_HEIGHT_LINES);
uint16_t checksum = __state.checksum;
stateReset();
portStoryLoad();
__state.checksum = checksum;
opcodesSetup();
storySetup(width, height);
}
void opcodes_restore(void) {
bool ok = portFileRestore();
uint16_t oldLines = __state.statusWindowLineCount;
bool ok = portFileRestore();
// Collapse upper window.
__state.statusWindowLineCount = 0;
windowSplit(0);
if (ok) {
// Collapse upper window.
__state.statusWindowLineCount = 0;
windowSplit(0);
}
interpreterDoBranch(ok ? 1 : 0);
}

View file

@ -26,6 +26,20 @@
#include "memory.h"
void storyChecksumCalculate(void) {
uint32_t i;
__state.checksum = 0;
for (i=64; i<storyLength(); i++) __state.checksum += ZPEEK(i);
__state.checksum %= 0x10000;
#ifdef DEBUGGING
printf("\n\nChecksum = %u Header = %d\n\n", __state.checksum, storyChecksum());
#endif
}
uint32_t storyLength() {
uint32_t m = (uint32_t)storyFileSize() * 2;

View file

@ -32,6 +32,10 @@
#include "lib.h"
static void textMoreCheck(void);
static void textNumPrint_r(int32_t val);
void textCharPrint(char c) {
static char lineBuffer[256];
static uint16_t lineWidth = 0;
@ -53,7 +57,7 @@ void textCharPrint(char c) {
if (!__state.outputting) return;
// Do we need to word wrap?
if (lineWidth == width - 2) {
if (lineWidth == width - 1) {
// Are we printing a space or CR? If so, just go to next line.
if ((c == ' ') || (c == '\n')) {
c = '\n';
@ -77,9 +81,11 @@ void textCharPrint(char c) {
}
// Wrap display.
portCharPrint('\n');
__state.linesOut++;
// Move erased characters to front of buffer & redisplay.
portCharGetPos(&x, &y);
portCharSetPos(1, y);
textMoreCheck();
x = 0;
for (i=space; i<=lineWidth; i++) {
lineBuffer[x++] = lineBuffer[i];
@ -97,12 +103,32 @@ void textCharPrint(char c) {
if (c == '\n') {
// New line.
lineWidth = 0;
__state.linesOut++;
textMoreCheck();
} else {
lineBuffer[lineWidth++] = c;
}
}
static void textMoreCheck(void) {
byte x;
byte y;
if (__state.linesOut >= storyScreenHeightLines() - __state.statusWindowLineCount - 1) {
// Display [MORE] prompt.
portCharGetPos(&x, &y);
textStringPrint("[MORE]");
textStringPrint(" ");
portCharGet();
portCharSetPos(x, y);
textStringPrint(" ");
portCharSetPos(x, y);
__state.linesOut = 0;
}
}
static void textNumPrint_r(int32_t val) {
if (val > 9) {
@ -212,5 +238,18 @@ void textStringPrint(char *s) {
void textTimePrint(uint16_t hours, uint16_t minutes) {
bool PM = (hours < 12) ? false : true;
hours %= 12;
if (hours == 0) hours = 12;
if (hours < 10) textCharPrint(' ');
textNumPrint(hours);
textCharPrint(':');
if (minutes < 10) textCharPrint('0');
textNumPrint(minutes);
textStringPrint((PM ? " pm" : " am"));
}

View file

@ -61,7 +61,7 @@ uint8_t variableAddress(uint8_t var, bool writing) {
if (writing) {
if (__state.sp >= sizeof(__state.stack)) portDie(MSG_INT_STACK_OVERFLOW);
#ifdef DEBUGGING
#ifdef DEBUGGINGx
printf("Push stack\n");
#endif
return __state.sp++;
@ -71,7 +71,7 @@ uint8_t variableAddress(uint8_t var, bool writing) {
if (__state.sp == 0) portDie(MSG_INT_STACK_UNDERFLOW);
numLocals = __state.bp ? __state.stack[__state.bp - 1] : 0;
if ((__state.bp + numLocals) >= sizeof(__state.stack)) portDie(MSG_INT_STACK_UNDERFLOW);
#ifdef DEBUGGING
#ifdef DEBUGGINGx
printf("Pop stack\n");
#endif
return --__state.sp;

View file

@ -130,9 +130,11 @@ void windowSplit(byte newLines) {
void windowUpdateStatusBar(void) {
byte width = storyScreenWidthCharacters() - 1;
windowSet(WINDOW_STATUS);
portCharSetPos(1, 1);
// Reverse attribute.
portAttributeSet(TEXT_ATTR_REVERSE);
textOutputStream(STREAM_OUTPUT_MEMORY, 0);
windowPadStatus(1);
@ -142,26 +144,26 @@ void windowUpdateStatusBar(void) {
if ((storyFlags() & STORY_STATUS_MASK) == STORY_STATUS_HOURS_MINUTES) {
// Timed game.
windowPadStatus(storyScreenWidthCharacters() - 21);
windowPadStatus(width - 21);
textStringPrint(" Time: ");
textTimePrint(variableLoad(17), variableLoad(18));
} else {
// Scored game.
windowPadStatus(storyScreenWidthCharacters() - 31);
windowPadStatus(width - 31);
textStringPrint(" Score: ");
textNumPrint(variableLoad(17));
windowPadStatus(storyScreenWidthCharacters() - 15);
windowPadStatus(width - 15);
textStringPrint(" Moves: ");
textNumPrint(variableLoad(18));
}
windowPadStatus(storyScreenWidthCharacters());
windowPadStatus(width);
__state.statusBar[__state.statusBarLen] = 0;
textOutputStream(-STREAM_OUTPUT_MEMORY, 0);
textStringPrint(__state.statusBar);
// Normal attribute.
portAttributeSet(TEXT_ATTR_NORMAL);
windowSet(WINDOW_TEXT);
}