F256 port added. llvm-mos lld is not happy about it.
This commit is contained in:
parent
389592fc12
commit
75a8bc61bc
36 changed files with 806 additions and 275 deletions
8
.gitignore
vendored
8
.gitignore
vendored
|
@ -4,9 +4,17 @@
|
||||||
# Stuff I've downloaded
|
# Stuff I've downloaded
|
||||||
stuff/
|
stuff/
|
||||||
|
|
||||||
|
# ZIP tests.
|
||||||
|
tests/
|
||||||
|
|
||||||
# Story files
|
# Story files
|
||||||
stories/
|
stories/
|
||||||
|
|
||||||
|
# Build files.
|
||||||
|
.builddir/
|
||||||
|
*.o
|
||||||
|
*.pgz
|
||||||
|
|
||||||
# Dumb QtCreator junk
|
# Dumb QtCreator junk
|
||||||
build-*/
|
build-*/
|
||||||
*.user
|
*.user
|
||||||
|
|
|
@ -5,6 +5,7 @@ project(zip LANGUAGES C)
|
||||||
set(HEADERS
|
set(HEADERS
|
||||||
common.h
|
common.h
|
||||||
interpreter.h
|
interpreter.h
|
||||||
|
lib.h
|
||||||
memory.h
|
memory.h
|
||||||
messages.h
|
messages.h
|
||||||
object.h
|
object.h
|
||||||
|
@ -25,13 +26,14 @@ set(HEADERS
|
||||||
story.h
|
story.h
|
||||||
variable.h
|
variable.h
|
||||||
zscii.h
|
zscii.h
|
||||||
|
# czech.z3.h
|
||||||
zork1.h
|
zork1.h
|
||||||
)
|
)
|
||||||
list(TRANSFORM HEADERS PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/include/")
|
list(TRANSFORM HEADERS PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/include/")
|
||||||
|
|
||||||
set(SOURCE
|
set(SOURCE
|
||||||
interpreter.c
|
interpreter.c
|
||||||
main.c
|
lib.c
|
||||||
memory.c
|
memory.c
|
||||||
object.c
|
object.c
|
||||||
oc_call.c
|
oc_call.c
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
#define DEBUGGING
|
//#define DEBUGGING
|
||||||
|
|
||||||
|
|
||||||
#ifdef DEBUGGING
|
#ifdef DEBUGGING
|
||||||
|
|
36
include/lib.h
Normal file
36
include/lib.h
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Scott Duensing, scott@kangaroopunch.com
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef LIB_H
|
||||||
|
#define LIB_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
|
||||||
|
void libMemSet(byte *start, byte val, uint32_t len);
|
||||||
|
char *libStrChr(char *haystack, char needle);
|
||||||
|
uint32_t libStrLen(char *str);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // LIB_H
|
|
@ -40,13 +40,6 @@
|
||||||
#define ZPOKEW(a,v) portWordSet(a,v)
|
#define ZPOKEW(a,v) portWordSet(a,v)
|
||||||
|
|
||||||
|
|
||||||
extern char *__memoryBuffer;
|
|
||||||
extern uint16_t __memoryBufferLen;
|
|
||||||
|
|
||||||
|
|
||||||
void memoryEnsureBuffer(uint32_t newSize);
|
|
||||||
void memoryShutdown(void);
|
|
||||||
void memoryStartup(void);
|
|
||||||
uint32_t memoryUnpackAddress(uint16_t address, uint8_t type);
|
uint32_t memoryUnpackAddress(uint16_t address, uint8_t type);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
#define MSG_INT_V12_SHIFT "Add V1/V2 shifting."
|
#define MSG_INT_V12_SHIFT "Add V1/V2 shifting."
|
||||||
#define MSG_INT_V12_SHIFT_LOCK "Add V1/V2 shift locking."
|
#define MSG_INT_V12_SHIFT_LOCK "Add V1/V2 shift locking."
|
||||||
#define MSG_MEM_BUFFER "Unable to allocate memory buffer."
|
#define MSG_MEM_BUFFER "Unable to allocate memory buffer."
|
||||||
|
#define MSG_OP_INP_BUFFER_TOO_SMALL "Text buffer too small for reading."
|
||||||
#define MSG_OP_OBJ_MISSING_PROPERTY "Missing object property."
|
#define MSG_OP_OBJ_MISSING_PROPERTY "Missing object property."
|
||||||
#define MSG_OP_VAR_TOO_MANY_LOCALS "Too many local variables!"
|
#define MSG_OP_VAR_TOO_MANY_LOCALS "Too many local variables!"
|
||||||
#define MSG_OP_VAR_STACK_OVERFLOW "Stack overflow!"
|
#define MSG_OP_VAR_STACK_OVERFLOW "Stack overflow!"
|
||||||
|
@ -57,7 +58,8 @@
|
||||||
#define MSG_INT_V12_SHIFT ""
|
#define MSG_INT_V12_SHIFT ""
|
||||||
#define MSG_INT_V12_SHIFT_LOCK ""
|
#define MSG_INT_V12_SHIFT_LOCK ""
|
||||||
#define MSG_MEM_BUFFER ""
|
#define MSG_MEM_BUFFER ""
|
||||||
#define MSG_OP_VAR_MISSING_PROPERTY ""
|
#define MSG_OP_INP_BUFFER_TOO_SMALL ""
|
||||||
|
#define MSG_OP_OBJ_MISSING_PROPERTY ""
|
||||||
#define MSG_OP_VAR_TOO_MANY_LOCALS ""
|
#define MSG_OP_VAR_TOO_MANY_LOCALS ""
|
||||||
#define MSG_OP_VAR_STACK_OVERFLOW ""
|
#define MSG_OP_VAR_STACK_OVERFLOW ""
|
||||||
#endif // DEBUGGING
|
#endif // DEBUGGING
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
uint32_t objectPointerGet(uint16_t objectId);
|
uint32_t objectPointerGet(uint16_t objectId);
|
||||||
uint32_t objectPointerParentGet(uint32_t objectPointer);
|
uint32_t objectPointerParentGet(uint32_t objectPointer);
|
||||||
uint16_t objectPropertyDefaultGet(uint32_t propertyId);
|
uint16_t objectPropertyDefaultGet(uint32_t propertyId);
|
||||||
uint8_t objectPropertyGet(uint16_t objectId, uint32_t propertyId, uint8_t *size);
|
uint32_t objectPropertyGet(uint16_t objectId, uint32_t propertyId, uint8_t *size);
|
||||||
uint16_t objectRelationGet(uint16_t objectId, uint8_t relationship);
|
uint16_t objectRelationGet(uint16_t objectId, uint8_t relationship);
|
||||||
void objectUnparent(uint16_t objectId);
|
void objectUnparent(uint16_t objectId);
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@ void opcodes_div(void);
|
||||||
void opcodes_inc(void);
|
void opcodes_inc(void);
|
||||||
void opcodes_mod(void);
|
void opcodes_mod(void);
|
||||||
void opcodes_mul(void);
|
void opcodes_mul(void);
|
||||||
|
void opcodes_not(void);
|
||||||
void opcodes_or(void);
|
void opcodes_or(void);
|
||||||
void opcodes_sub(void);
|
void opcodes_sub(void);
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,9 @@
|
||||||
void opcodes_load(void);
|
void opcodes_load(void);
|
||||||
void opcodes_loadb(void);
|
void opcodes_loadb(void);
|
||||||
void opcodes_loadw(void);
|
void opcodes_loadw(void);
|
||||||
|
void opcodes_pop(void);
|
||||||
|
void opcodes_pull(void);
|
||||||
|
void opcodes_push(void);
|
||||||
void opcodes_store(void);
|
void opcodes_store(void);
|
||||||
void opcodes_storeb(void);
|
void opcodes_storeb(void);
|
||||||
void opcodes_storew(void);
|
void opcodes_storew(void);
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
void opcodes_nop(void);
|
void opcodes_nop(void);
|
||||||
void opcodes_quit(void);
|
void opcodes_quit(void);
|
||||||
void opcodes_random(void);
|
void opcodes_random(void);
|
||||||
|
void opcodes_verify(void);
|
||||||
|
|
||||||
|
|
||||||
#endif // OC_MISC_H
|
#endif // OC_MISC_H
|
||||||
|
|
|
@ -30,13 +30,11 @@
|
||||||
|
|
||||||
uint8_t portByteGet(uint16_t address);
|
uint8_t portByteGet(uint16_t address);
|
||||||
void portByteSet(uint16_t address, uint8_t value);
|
void portByteSet(uint16_t address, uint8_t value);
|
||||||
void portCharsPrint(char *chars, uint16_t len);
|
void portCharPrint(char c);
|
||||||
void portDie(char *fmt, ...);
|
void portDie(char *fmt, ...);
|
||||||
void portFileClose(uint32_t *handle);
|
bool portFileRestore(void);
|
||||||
byte portFileByteRead(uint32_t *handle);
|
bool portFileSave(void);
|
||||||
bool portFileByteWrite(uint32_t *handle, byte value);
|
void portInput(uint32_t ramAddr, uint8_t length);
|
||||||
bool portFileReadOpen(uint32_t *handle, char *name);
|
|
||||||
bool portFileWriteOpen(uint32_t *handle, char *name);
|
|
||||||
uint16_t portRandomGet(int16_t range);
|
uint16_t portRandomGet(int16_t range);
|
||||||
void portStoryLoad(void);
|
void portStoryLoad(void);
|
||||||
uint16_t portWordGet(uint16_t address);
|
uint16_t portWordGet(uint16_t address);
|
||||||
|
|
|
@ -85,6 +85,7 @@
|
||||||
#define storyStaticMemoryBaseAddress() portWordGet(0xe)
|
#define storyStaticMemoryBaseAddress() portWordGet(0xe)
|
||||||
#define storyFlags2() portWordGet(0x10)
|
#define storyFlags2() portWordGet(0x10)
|
||||||
#define storyAbbreviationTableAddress() portWordGet(0x18)
|
#define storyAbbreviationTableAddress() portWordGet(0x18)
|
||||||
|
#define storyFileSize() portWordGet(0x1a)
|
||||||
#define storyChecksum() portWordGet(0x1c)
|
#define storyChecksum() portWordGet(0x1c)
|
||||||
#define storyInterpreterNumber() portByteGet(0x1e)
|
#define storyInterpreterNumber() portByteGet(0x1e)
|
||||||
#define storyInterpreterVersion() portByteGet(0x1f)
|
#define storyInterpreterVersion() portByteGet(0x1f)
|
||||||
|
|
|
@ -28,7 +28,6 @@
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
|
|
||||||
uint32_t zsciiDecode(uint32_t zstr, bool abbr, char *buf, uint32_t *bufLenP);
|
|
||||||
char zsciiDecodeChar(uint16_t z);
|
char zsciiDecodeChar(uint16_t z);
|
||||||
uint32_t zsciiPrint(uint32_t pc, bool abbr);
|
uint32_t zsciiPrint(uint32_t pc, bool abbr);
|
||||||
|
|
||||||
|
|
63
ports/f256/CMakeLists.txt
Normal file
63
ports/f256/CMakeLists.txt
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
cmake_minimum_required(VERSION 3.12)
|
||||||
|
|
||||||
|
project(zip LANGUAGES C)
|
||||||
|
|
||||||
|
set(HEADERS
|
||||||
|
common.h
|
||||||
|
interpreter.h
|
||||||
|
lib.h
|
||||||
|
memory.h
|
||||||
|
messages.h
|
||||||
|
object.h
|
||||||
|
oc_call.h
|
||||||
|
oc_compare.h
|
||||||
|
oc_input.h
|
||||||
|
oc_math.h
|
||||||
|
oc_memory.h
|
||||||
|
oc_misc.h
|
||||||
|
oc_object.h
|
||||||
|
oc_output.h
|
||||||
|
oc_save.h
|
||||||
|
oc_window.h
|
||||||
|
opcodes.h
|
||||||
|
portme.h
|
||||||
|
state.h
|
||||||
|
stddclmr.h
|
||||||
|
story.h
|
||||||
|
variable.h
|
||||||
|
zscii.h
|
||||||
|
# czech.z3.h
|
||||||
|
# zork1.h
|
||||||
|
)
|
||||||
|
list(TRANSFORM HEADERS PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/../../include/")
|
||||||
|
|
||||||
|
set(SOURCE
|
||||||
|
interpreter.c
|
||||||
|
lib.c
|
||||||
|
memory.c
|
||||||
|
object.c
|
||||||
|
oc_call.c
|
||||||
|
oc_compare.c
|
||||||
|
oc_input.c
|
||||||
|
oc_math.c
|
||||||
|
oc_memory.c
|
||||||
|
oc_misc.c
|
||||||
|
oc_object.c
|
||||||
|
oc_output.c
|
||||||
|
oc_save.c
|
||||||
|
oc_window.c
|
||||||
|
opcodes.c
|
||||||
|
state.c
|
||||||
|
story.c
|
||||||
|
variable.c
|
||||||
|
zscii.c
|
||||||
|
)
|
||||||
|
list(TRANSFORM SOURCE PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/../../src/")
|
||||||
|
|
||||||
|
add_executable(${CMAKE_PROJECT_NAME}
|
||||||
|
${HEADERS}
|
||||||
|
${SOURCE}
|
||||||
|
f256zip.c
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(${CMAKE_PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../../include)
|
60
ports/f256/build.sh
Executable file
60
ports/f256/build.sh
Executable file
|
@ -0,0 +1,60 @@
|
||||||
|
#!/bin/bash -ex
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright (c) 2024 Scott Duensing, scott@kangaroopunch.com
|
||||||
|
#
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
|
# in the Software without restriction, including without limitation the rights
|
||||||
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
|
# furnished to do so, subject to the following conditions:
|
||||||
|
#
|
||||||
|
# The above copyright notice and this permission notice shall be included in
|
||||||
|
# all copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
# SOFTWARE.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
PROJECT=f256zip
|
||||||
|
START=0x200
|
||||||
|
|
||||||
|
F256=$(pwd)/../../../f256
|
||||||
|
LLVM=${F256}/llvm-mos
|
||||||
|
SETTINGS=${LLVM}/mos-platform/f256k/lib/settings.ld
|
||||||
|
PATH=${LLVM}/bin:${PATH}
|
||||||
|
|
||||||
|
echo "__f256_start = ${START};" > ${SETTINGS}
|
||||||
|
|
||||||
|
CLANG="mos-f256k-clang -I../../../include -I${F256}/include -I${F256}/f256lib -Os"
|
||||||
|
|
||||||
|
[[ -d .builddir ]] && rm -rf .builddir
|
||||||
|
mkdir -p .builddir
|
||||||
|
pushd .builddir
|
||||||
|
|
||||||
|
${CLANG} -c ${F256}/f256lib/f256.c
|
||||||
|
${CLANG} -c ../../../src/{interpreter,lib,memory,object,oc_call,oc_compare,oc_input,oc_math,oc_memory,oc_misc,oc_object,oc_output,oc_save,oc_window,opcodes,state,story,variable,zscii}.c
|
||||||
|
${CLANG} -c ../${PROJECT}.c
|
||||||
|
${CLANG} -o ${PROJECT} {interpreter,lib,memory,object,oc_call,oc_compare,oc_input,oc_math,oc_memory,oc_misc,oc_object,oc_output,oc_save,oc_window,opcodes,state,story,variable,zscii}.o f256.o ${PROJECT}.o
|
||||||
|
|
||||||
|
mv -f ${PROJECT} zip.bin
|
||||||
|
|
||||||
|
${F256}/header \
|
||||||
|
pgz 24 \
|
||||||
|
../${PROJECT}.pgz \
|
||||||
|
${START} \
|
||||||
|
${PROJECT}.bin ${START} \
|
||||||
|
../../../tests/testers/czech/czech.z3
|
||||||
|
|
||||||
|
#llvm-nm ${PROJECT}.elf > ${PROJECT}.lst
|
||||||
|
#llvm-objdump -d --print-imm-hex ${PROJECT}.elf > ${PROJECT}.lst
|
||||||
|
#hexdump -C ../${PROJECT}.pgz > ${PROJECT}.hex
|
||||||
|
|
||||||
|
popd
|
200
ports/f256/f256zip.c
Normal file
200
ports/f256/f256zip.c
Normal file
|
@ -0,0 +1,200 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Scott Duensing, scott@kangaroopunch.com
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Z-Machine for the Foenix F256 computers.
|
||||||
|
*
|
||||||
|
* F256 machines are 65c02 based systems with 512k of banked RAM.
|
||||||
|
* As such, this ZIP is going to load the story entirely into "high"
|
||||||
|
* memory (above the 64k accessable to the CPU) and page things in
|
||||||
|
* and out as needed.
|
||||||
|
*
|
||||||
|
* To keep library code at a minimum, we'll also statically allocate
|
||||||
|
* as much as possible and do other "bad" things now frowned upon in
|
||||||
|
* modern development. :-)
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "f256.h"
|
||||||
|
|
||||||
|
#include "portme.h"
|
||||||
|
#include "story.h"
|
||||||
|
#include "memory.h"
|
||||||
|
#include "state.h"
|
||||||
|
#include "interpreter.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define BASE_ADDRESS 0x10000
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t portByteGet(uint16_t address) {
|
||||||
|
return FAR_PEEK(BASE_ADDRESS + address);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void portByteSet(uint16_t address, uint8_t value) {
|
||||||
|
FAR_POKE(BASE_ADDRESS + address, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void portCharPrint(char c) {
|
||||||
|
static char ch[2] = { 0, 0 };
|
||||||
|
ch[0] = c;
|
||||||
|
textPrint(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void portDie(char *fmt, ...) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool portFileRestore(void) {
|
||||||
|
|
||||||
|
FILE *in;
|
||||||
|
bool ok = false;
|
||||||
|
uint32_t i;
|
||||||
|
byte b;
|
||||||
|
|
||||||
|
in = fopen("save.dat", "rb");
|
||||||
|
if (in) {
|
||||||
|
ok = true;
|
||||||
|
|
||||||
|
// Read in PC.
|
||||||
|
ok &= (fread(&__state.pc, sizeof(__state.pc), 1, in) == 1);
|
||||||
|
// Read in SP.
|
||||||
|
ok &= (fread(&__state.sp, sizeof(__state.sp), 1, in) == 1);
|
||||||
|
// Read in BP.
|
||||||
|
ok &= (fread(&__state.bp, sizeof(__state.bp), 1, in) == 1);
|
||||||
|
// Read in dynamic game RAM.
|
||||||
|
for (i=0; i<storyStaticMemoryBaseAddress(); i++) {
|
||||||
|
ok &= (fread(&b, 1, 1, in) == 1);
|
||||||
|
ZPOKE(i, b);
|
||||||
|
}
|
||||||
|
// Read in stack.
|
||||||
|
ok &= (fread(__state.stack, sizeof(__state.stack[0]), __state.sp, in) == __state.sp);
|
||||||
|
|
||||||
|
fclose(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool portFileSave(void) {
|
||||||
|
FILE *out;
|
||||||
|
bool ok = false;
|
||||||
|
uint32_t i;
|
||||||
|
byte b;
|
||||||
|
|
||||||
|
out = fopen("save.dat", "wb");
|
||||||
|
if (out) {
|
||||||
|
ok = true;
|
||||||
|
|
||||||
|
// Write out PC.
|
||||||
|
ok &= (fwrite(&__state.pc, sizeof(__state.pc), 1, out) == 1);
|
||||||
|
// Write out SP.
|
||||||
|
ok &= (fwrite(&__state.sp, sizeof(__state.sp), 1, out) == 1);
|
||||||
|
// Write out BP.
|
||||||
|
ok &= (fwrite(&__state.bp, sizeof(__state.bp), 1, out) == 1);
|
||||||
|
// Write out dynamic game RAM.
|
||||||
|
for (i=0; i<storyStaticMemoryBaseAddress(); i++) {
|
||||||
|
b = ZPEEK(i);
|
||||||
|
ok &= (fwrite(&b, 1, 1, out) == 1);
|
||||||
|
}
|
||||||
|
// Write out stack.
|
||||||
|
ok &= (fwrite(__state.stack, sizeof(__state.stack[0]), __state.sp, out) == __state.sp);
|
||||||
|
|
||||||
|
fclose(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void portInput(uint32_t ramAddr, uint8_t length) {
|
||||||
|
uint8_t i;
|
||||||
|
char c;
|
||||||
|
|
||||||
|
for (i=0; i<length; i++) {
|
||||||
|
c = getchar();
|
||||||
|
ZPOKE(ramAddr, c);
|
||||||
|
if ((c == 13) || (c == 10)) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
if (range == 0) return 0;
|
||||||
|
|
||||||
|
if (range < 0) {
|
||||||
|
randomSeed(-range);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (randomRead() % range) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void portStoryLoad(void) {
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// Currently no status bar.
|
||||||
|
ZPOKE(STORY_FLAG_V3, ZPEEK(STORY_FLAG_V3) | STORY_FLAG_V3_STATUS_LINE_NOT_AVAILABLE);
|
||||||
|
|
||||||
|
// Uncomment for status bar and window splitting.
|
||||||
|
//POKE(STORY_FLAG_V3, PEEK(STORY_FLAG_V3) & ~STORY_FLAG_V3_STATUS_LINE_NOT_AVAILABLE);
|
||||||
|
//POKE(STORY_FLAG_V3, PEEK(STORY_FLAG_V3) | STORY_FLAG_V3_SCREEN_SPLITTING);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint16_t portWordGet(uint16_t address) {
|
||||||
|
return SWAP_UINT16(FAR_PEEKW(BASE_ADDRESS + address));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void portWordSet(uint16_t address, uint16_t value) {
|
||||||
|
FAR_POKEW(BASE_ADDRESS + address, SWAP_UINT16(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
|
||||||
|
f256Init();
|
||||||
|
|
||||||
|
textSetCursor(199);
|
||||||
|
|
||||||
|
stateReset();
|
||||||
|
portStoryLoad();
|
||||||
|
opcodesSetup();
|
||||||
|
storySetup();
|
||||||
|
interpreterRun();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
7
ports/f256/foenixmgr.ini
Normal file
7
ports/f256/foenixmgr.ini
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
[DEFAULT]
|
||||||
|
port=/dev/ttyUSB1
|
||||||
|
labels=sample.lbl
|
||||||
|
flash_address=380000
|
||||||
|
chunk_size=1024
|
||||||
|
cpu=65c02
|
||||||
|
data_rate=6000000
|
26
ports/f256/run.sh
Executable file
26
ports/f256/run.sh
Executable file
|
@ -0,0 +1,26 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright (c) 2024 Scott Duensing, scott@kangaroopunch.com
|
||||||
|
#
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
|
# in the Software without restriction, including without limitation the rights
|
||||||
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
|
# furnished to do so, subject to the following conditions:
|
||||||
|
#
|
||||||
|
# The above copyright notice and this permission notice shall be included in
|
||||||
|
# all copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
# SOFTWARE.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
python ../../FoenixMgr/FoenixMgr/fnxmgr.py --run-pgz zip.pgz
|
|
@ -21,6 +21,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "stddclmr.h"
|
||||||
|
|
||||||
#include "interpreter.h"
|
#include "interpreter.h"
|
||||||
#include "portme.h"
|
#include "portme.h"
|
||||||
#include "messages.h"
|
#include "messages.h"
|
||||||
|
|
|
@ -21,38 +21,30 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/*
|
#include "lib.h"
|
||||||
* Z-Machine for the Foenix F256 computers.
|
|
||||||
*
|
|
||||||
* F256 machines are 65c02 based systems with 512k of banked RAM.
|
|
||||||
* As such, this ZIP is going to load the story entirely into "high"
|
|
||||||
* memory (above the 64k accessable to the CPU) and page things in
|
|
||||||
* and out as needed.
|
|
||||||
*
|
|
||||||
* To keep library code at a minimum, we'll also statically allocate
|
|
||||||
* as much as possible and do other "bad" things now frowned upon in
|
|
||||||
* modern development. :-)
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include "stddclmr.h"
|
void libMemSet(byte *start, byte val, uint32_t len) {
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
#include "memory.h"
|
for (i=0; i<len; i++) start[i] = val;
|
||||||
#include "opcodes.h"
|
}
|
||||||
#include "state.h"
|
|
||||||
#include "interpreter.h"
|
|
||||||
#include "story.h"
|
|
||||||
|
|
||||||
|
|
||||||
int main(void) {
|
char *libStrChr(char *haystack, char needle) {
|
||||||
|
uint32_t len = libStrLen(haystack);
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
memoryStartup();
|
for (i=0; i<len; i++) {
|
||||||
stateReset();
|
if (haystack[i] == needle) return &haystack[i];
|
||||||
opcodesSetup();
|
}
|
||||||
portStoryLoad();
|
|
||||||
storySetup();
|
|
||||||
interpreterRun();
|
|
||||||
memoryShutdown();
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t libStrLen(char *str) {
|
||||||
|
uint32_t l = 0;
|
||||||
|
while (str[l] != 0) l++;
|
||||||
|
return l;
|
||||||
|
}
|
32
src/memory.c
32
src/memory.c
|
@ -21,40 +21,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "story.h"
|
#include "story.h"
|
||||||
#include "portme.h"
|
|
||||||
#include "messages.h"
|
|
||||||
|
|
||||||
|
|
||||||
// Generic buffer for whatever.
|
|
||||||
char *__memoryBuffer = 0;
|
|
||||||
uint16_t __memoryBufferLen = 0;
|
|
||||||
|
|
||||||
|
|
||||||
void memoryEnsureBuffer(uint32_t newSize) {
|
|
||||||
if (__memoryBufferLen >= newSize) return;
|
|
||||||
free(__memoryBuffer);
|
|
||||||
while (__memoryBufferLen < newSize) {
|
|
||||||
__memoryBufferLen += 512;
|
|
||||||
}
|
|
||||||
__memoryBuffer = (char *)malloc(__memoryBufferLen);
|
|
||||||
if (__memoryBuffer == 0) portDie(MSG_MEM_BUFFER);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void memoryShutdown(void) {
|
|
||||||
free(__memoryBuffer);
|
|
||||||
__memoryBuffer = 0;
|
|
||||||
__memoryBufferLen = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void memoryStartup(void) {
|
|
||||||
memoryEnsureBuffer(1024);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
uint32_t memoryUnpackAddress(uint16_t address, uint8_t type) {
|
uint32_t memoryUnpackAddress(uint16_t address, uint8_t type) {
|
||||||
|
|
|
@ -71,7 +71,7 @@ uint16_t objectPropertyDefaultGet(uint32_t propertyId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint8_t objectPropertyGet(uint16_t objectId, uint32_t propertyId, uint8_t *size) {
|
uint32_t objectPropertyGet(uint16_t objectId, uint32_t propertyId, uint8_t *size) {
|
||||||
uint32_t ptr = objectPointerGet(objectId);
|
uint32_t ptr = objectPointerGet(objectId);
|
||||||
uint16_t addr;
|
uint16_t addr;
|
||||||
uint8_t info;
|
uint8_t info;
|
||||||
|
@ -112,7 +112,7 @@ uint16_t objectRelationGet(uint16_t objectId, uint8_t relationship) {
|
||||||
uint16_t result = 0;
|
uint16_t result = 0;
|
||||||
|
|
||||||
if (storyVersion() <= 3) {
|
if (storyVersion() <= 3) {
|
||||||
result = ZPEEKW(objPtr + relationship);
|
result = ZPEEK(objPtr + relationship);
|
||||||
} else {
|
} else {
|
||||||
portDie(MSG_UNIMPLEMENTED);
|
portDie(MSG_UNIMPLEMENTED);
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,7 @@ void opcodes_jin(void) {
|
||||||
if (objPtr == 0) return;
|
if (objPtr == 0) return;
|
||||||
|
|
||||||
if (storyVersion() <= 3) {
|
if (storyVersion() <= 3) {
|
||||||
interpreterDoBranch((ZPEEKW(objPtr + 4) == parentId) ? 1 : 0);
|
interpreterDoBranch((ZPEEK(objPtr + 4) == parentId) ? 1 : 0);
|
||||||
} else {
|
} else {
|
||||||
portDie(MSG_UNIMPLEMENTED);
|
portDie(MSG_UNIMPLEMENTED);
|
||||||
}
|
}
|
||||||
|
@ -100,6 +100,6 @@ void opcodes_jz(void) {
|
||||||
|
|
||||||
|
|
||||||
void opcodes_test(void) {
|
void opcodes_test(void) {
|
||||||
interpreterDoBranch(((__state.operands[0] & __state.operands[1]) == __state.operands[0]) ? 1 : 0);
|
interpreterDoBranch(((__state.operands[0] & __state.operands[1]) == __state.operands[1]) ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
176
src/oc_input.c
176
src/oc_input.c
|
@ -23,10 +23,184 @@
|
||||||
|
|
||||||
#include "oc_input.h"
|
#include "oc_input.h"
|
||||||
#include "portme.h"
|
#include "portme.h"
|
||||||
|
#include "state.h"
|
||||||
|
#include "memory.h"
|
||||||
#include "messages.h"
|
#include "messages.h"
|
||||||
|
#include "story.h"
|
||||||
|
#include "lib.h"
|
||||||
|
|
||||||
|
|
||||||
void opcodes_read(void) {
|
void opcodes_read(void) {
|
||||||
|
static char tableA2v1[] = "0123456789.,!?_#\'\"/\\<-:()";
|
||||||
|
static char tableA2v2plus[] = "\n0123456789.,!?_#\'\"/\\-:()";
|
||||||
|
uint32_t input = __state.operands[0];
|
||||||
|
byte inputLen = ZPEEK(input++);
|
||||||
|
uint32_t parse = __state.operands[1];
|
||||||
|
byte parseLen = ZPEEK(parse++);
|
||||||
|
char *tableA2 = (storyVersion() <= 1) ? tableA2v1 : tableA2v2plus;
|
||||||
|
uint32_t seps = storyDictionaryAddress();
|
||||||
|
byte numSeps = ZPEEK(seps++);
|
||||||
|
uint32_t dict = seps + numSeps;
|
||||||
|
byte entryLen = ZPEEK(dict++);
|
||||||
|
uint16_t numEntries = ZPEEKW(dict);
|
||||||
|
byte numToks = 0;
|
||||||
|
uint32_t strStart;
|
||||||
|
uint32_t ptr;
|
||||||
|
byte *ptr2;
|
||||||
|
bool isSep;
|
||||||
|
byte ch;
|
||||||
|
byte i;
|
||||||
|
uint16_t encoded[3];
|
||||||
|
byte tokLen;
|
||||||
|
byte zChars[12];
|
||||||
|
byte zChIdx;
|
||||||
|
byte pos;
|
||||||
|
uint32_t dictPtr;
|
||||||
|
uint16_t zscii1;
|
||||||
|
uint16_t zscii2;
|
||||||
|
uint16_t zscii3;
|
||||||
|
|
||||||
|
dict += 2;
|
||||||
|
|
||||||
|
#ifdef DEBUGGING
|
||||||
|
printf("Read from input stream: text-buffer=%X parse-buffer=%X\n", (unsigned int)__state.operands[0], (unsigned int)__state.operands[1]);
|
||||||
|
printf("Max input: %u\n", inputLen);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (inputLen < 3) portDie(MSG_OP_INP_BUFFER_TOO_SMALL);
|
||||||
|
|
||||||
//***TODO***
|
//***TODO***
|
||||||
portDie(MSG_UNIMPLEMENTED);
|
//interpreterUpdateStatusBar();
|
||||||
|
|
||||||
|
// Read input from user.
|
||||||
|
portInput(input, inputLen);
|
||||||
|
|
||||||
|
#ifdef DEBUGGING
|
||||||
|
printf("Input string from user is '%s'\n", __memoryBuffer);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Tidy up input.
|
||||||
|
for (i=input; i<input+inputLen; i++) {
|
||||||
|
ch = ZPEEK(i);
|
||||||
|
if ((ch >= 'A') && (ch <= 'Z')) {
|
||||||
|
// Make lowercase.
|
||||||
|
ch -= 'A' - 'a';
|
||||||
|
ZPOKE(i, ch);
|
||||||
|
} else if ((ch == '\n') || (ch == '\r')) {
|
||||||
|
// End of line, end of input.
|
||||||
|
ch = 0;
|
||||||
|
ZPOKE(i, ch);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tokenize input.
|
||||||
|
strStart = input;
|
||||||
|
ptr = input;
|
||||||
|
while (1) {
|
||||||
|
isSep = false;
|
||||||
|
ch = ZPEEK(ptr);
|
||||||
|
|
||||||
|
if ((ch == ' ') || (ch == 0)) {
|
||||||
|
isSep = true;
|
||||||
|
} else {
|
||||||
|
for (i=0; i<numSeps; i++) {
|
||||||
|
if (ch == ZPEEK(seps + i)) {
|
||||||
|
isSep = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // isSep
|
||||||
|
|
||||||
|
if (isSep) {
|
||||||
|
encoded[0] = 0;
|
||||||
|
encoded[1] = 0;
|
||||||
|
encoded[2] = 0;
|
||||||
|
|
||||||
|
tokLen = ptr - strStart;
|
||||||
|
if (tokLen == 0) break; // Ran out of string.
|
||||||
|
|
||||||
|
zChIdx = 0;
|
||||||
|
for (i=0; i<tokLen; i++) {
|
||||||
|
ch = ZPEEK(strStart + i);
|
||||||
|
if ((ch >= 'a') && (ch <= 'z')) {
|
||||||
|
zChars[zChIdx++] = ((ch - 'a') + 6);
|
||||||
|
} else {
|
||||||
|
ptr2 = (byte *)libStrChr(tableA2, ch);
|
||||||
|
if (ptr2) {
|
||||||
|
// Command char to shift to table A2 for just the next char.
|
||||||
|
zChars[zChIdx++] = 3;
|
||||||
|
// +1 because the first table entry is a different piece of magic.
|
||||||
|
zChars[zChIdx++] = ((ptr2 - (byte *)tableA2) + 1) + 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (zChIdx >= (sizeof(zChars) / sizeof(zChars[0]))) break;
|
||||||
|
} // for
|
||||||
|
|
||||||
|
pos = 0;
|
||||||
|
encoded[0] |= ((pos < zChIdx) ? zChars[pos++] : 5) << 10;
|
||||||
|
encoded[0] |= ((pos < zChIdx) ? zChars[pos++] : 5) << 5;
|
||||||
|
encoded[0] |= ((pos < zChIdx) ? zChars[pos++] : 5) << 0;
|
||||||
|
encoded[1] |= ((pos < zChIdx) ? zChars[pos++] : 5) << 10;
|
||||||
|
encoded[1] |= ((pos < zChIdx) ? zChars[pos++] : 5) << 5;
|
||||||
|
encoded[1] |= ((pos < zChIdx) ? zChars[pos++] : 5) << 0;
|
||||||
|
|
||||||
|
dictPtr = dict;
|
||||||
|
if (storyVersion() <= 3) {
|
||||||
|
|
||||||
|
encoded[1] |= 0x8000;
|
||||||
|
for (i=0; i<numEntries; i++) {
|
||||||
|
zscii1 = ZPEEKW(dictPtr); dictPtr += 2;
|
||||||
|
zscii2 = ZPEEKW(dictPtr); dictPtr += 2;
|
||||||
|
if ((encoded[0] == zscii1) && (encoded[1] == zscii2)) {
|
||||||
|
dictPtr -= 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dictPtr += (entryLen - 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else { // V3
|
||||||
|
|
||||||
|
encoded[2] |= ((pos < zChIdx) ? zChars[pos++] : 5) << 10;
|
||||||
|
encoded[2] |= ((pos < zChIdx) ? zChars[pos++] : 5) << 5;
|
||||||
|
encoded[2] |= ((pos < zChIdx) ? zChars[pos++] : 5) << 0;
|
||||||
|
encoded[2] |= 0x8000;
|
||||||
|
|
||||||
|
for (i=0; i<numEntries; i++) {
|
||||||
|
zscii1 = ZPEEKW(dictPtr); dictPtr += 2;
|
||||||
|
zscii2 = ZPEEKW(dictPtr); dictPtr += 2;
|
||||||
|
zscii3 = ZPEEKW(dictPtr); dictPtr += 2;
|
||||||
|
if ((encoded[0] == zscii1) && (encoded[1] == zscii2) && (encoded[2] == zscii3)) {
|
||||||
|
dictPtr -= 6;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dictPtr += (entryLen - 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // V3
|
||||||
|
|
||||||
|
if (i == numEntries) dictPtr = 0; // Not Found.
|
||||||
|
|
||||||
|
ZPOKEW(parse, dictPtr);
|
||||||
|
parse += 2;
|
||||||
|
ZPOKE(parse++, tokLen);
|
||||||
|
ZPOKE(parse++, strStart - input + 1);
|
||||||
|
numToks++;
|
||||||
|
|
||||||
|
if (numToks >= parseLen) break; // Ran out of space.
|
||||||
|
|
||||||
|
strStart = ptr + 1;
|
||||||
|
} // if isSep
|
||||||
|
|
||||||
|
if (ch == 0) break; // End of string.
|
||||||
|
|
||||||
|
ptr++;
|
||||||
|
|
||||||
|
} // while
|
||||||
|
|
||||||
|
#ifdef DEBUGGING
|
||||||
|
printf("Tokenized %u tokens\n", (unsigned int)numToks);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ZPOKE(__state.operands[1] + 1, numToks);
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,6 +62,11 @@ void opcodes_mul(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void opcodes_not(void) {
|
||||||
|
variableStore(ZPEEK(__state.pc++), ~__state.operands[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void opcodes_or(void) {
|
void opcodes_or(void) {
|
||||||
variableStore(ZPEEK(__state.pc++), __state.operands[0] | __state.operands[1]);
|
variableStore(ZPEEK(__state.pc++), __state.operands[0] | __state.operands[1]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,10 @@
|
||||||
|
|
||||||
|
|
||||||
void opcodes_load(void) {
|
void opcodes_load(void) {
|
||||||
variableStore(ZPEEK(__state.pc++), ZPEEK((__state.operands[0] & 0xFF)));
|
uint8_t dst = ZPEEK(__state.pc++);
|
||||||
|
uint8_t src = (uint8_t)(__state.operands[0] & 0xFF);
|
||||||
|
int16_t val = variableLoad(src);
|
||||||
|
variableStore(dst, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -44,6 +47,21 @@ void opcodes_loadw(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void opcodes_pop(void) {
|
||||||
|
variableAddress(0, 0); // Causes a pop.
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void opcodes_pull(void) {
|
||||||
|
variableStore((__state.operands[0] & 0xFF), variableLoad(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void opcodes_push(void) {
|
||||||
|
variableStore(0, __state.operands[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void opcodes_store(void) {
|
void opcodes_store(void) {
|
||||||
variableStore((__state.operands[0] & 0xFF), __state.operands[1]);
|
variableStore((__state.operands[0] & 0xFF), __state.operands[1]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,9 @@
|
||||||
#include "state.h"
|
#include "state.h"
|
||||||
#include "variable.h"
|
#include "variable.h"
|
||||||
#include "portme.h"
|
#include "portme.h"
|
||||||
|
#include "story.h"
|
||||||
|
#include "memory.h"
|
||||||
|
#include "interpreter.h"
|
||||||
|
|
||||||
|
|
||||||
void opcodes_nop(void) {
|
void opcodes_nop(void) {
|
||||||
|
@ -40,3 +43,14 @@ void opcodes_quit(void) {
|
||||||
void opcodes_random(void) {
|
void opcodes_random(void) {
|
||||||
variableStore((__state.pc++), portRandomGet((int16_t)__state.operands[0]));
|
variableStore((__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);
|
||||||
|
i = storyChecksum();
|
||||||
|
|
||||||
|
interpreterDoBranch(checksum == storyChecksum() ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
|
@ -80,7 +80,6 @@ void opcodes_get_next_prop(void) {
|
||||||
void opcodes_get_parent(void) {
|
void opcodes_get_parent(void) {
|
||||||
uint16_t result = objectRelationGet(__state.operands[0], 4);
|
uint16_t result = objectRelationGet(__state.operands[0], 4);
|
||||||
variableStore(ZPEEK(__state.pc++), result);
|
variableStore(ZPEEK(__state.pc++), result);
|
||||||
interpreterDoBranch(result != 0 ? 1 : 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -93,8 +92,10 @@ void opcodes_get_prop(void) {
|
||||||
|
|
||||||
if (ptr == 0) {
|
if (ptr == 0) {
|
||||||
result = objectPropertyDefaultGet(propId);
|
result = objectPropertyDefaultGet(propId);
|
||||||
} else {
|
} else if (size == 1) {
|
||||||
result = ZPEEK(ptr);
|
result = ZPEEK(ptr);
|
||||||
|
} else {
|
||||||
|
result = ZPEEKW(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
variableStore(ZPEEK(__state.pc++), result);
|
variableStore(ZPEEK(__state.pc++), result);
|
||||||
|
@ -105,7 +106,7 @@ void opcodes_get_prop_addr(void) {
|
||||||
uint16_t objId = __state.operands[0];
|
uint16_t objId = __state.operands[0];
|
||||||
uint16_t propId = __state.operands[1];
|
uint16_t propId = __state.operands[1];
|
||||||
|
|
||||||
variableStore(ZPEEK(__state.pc++), objectPropertyGet(objId, propId, NULL));
|
variableStore(ZPEEK(__state.pc++), objectPropertyGet(objId, propId, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -152,8 +153,8 @@ void opcodes_insert_obj(void) {
|
||||||
|
|
||||||
|
|
||||||
void opcodes_put_prop(void) {
|
void opcodes_put_prop(void) {
|
||||||
uint8_t size = 0;
|
uint8_t size = 0;
|
||||||
uint8_t ptr = objectPropertyGet(__state.operands[0], __state.operands[1], &size);
|
uint32_t ptr = objectPropertyGet(__state.operands[0], __state.operands[1], &size);
|
||||||
|
|
||||||
if (ptr == 0) portDie(MSG_OP_OBJ_MISSING_PROPERTY);
|
if (ptr == 0) portDie(MSG_OP_OBJ_MISSING_PROPERTY);
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
|
|
||||||
|
|
||||||
void opcodes_new_line(void) {
|
void opcodes_new_line(void) {
|
||||||
portCharsPrint("\n", 1);
|
portCharPrint('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -48,32 +48,29 @@ void opcodes_print_addr(void) {
|
||||||
|
|
||||||
|
|
||||||
void opcodes_print_char(void) {
|
void opcodes_print_char(void) {
|
||||||
static char c[2] = { 0, 0 };
|
char c = zsciiDecodeChar(__state.operands[0]);
|
||||||
|
if (c) portCharPrint(c);
|
||||||
c[0] = zsciiDecodeChar(__state.operands[0]);
|
|
||||||
if (c[0]) portCharsPrint(c, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void opcodes_print_num_helper(int16_t val) {
|
void opcodes_print_num_r(int32_t val) {
|
||||||
static char c[2] = { 0, 0 };
|
|
||||||
|
|
||||||
if (val < 0) {
|
|
||||||
portCharsPrint("-", 1);
|
|
||||||
val = -val;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (val > 9) {
|
if (val > 9) {
|
||||||
opcodes_print_num_helper(val / 10);
|
opcodes_print_num_r(val / 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
c[0] = '0' + (val % 10);
|
portCharPrint('0' + (val % 10));
|
||||||
portCharsPrint(c, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void opcodes_print_num(void) {
|
void opcodes_print_num(void) {
|
||||||
opcodes_print_num_helper(__state.operands[0]);
|
int32_t n = (int16_t)__state.operands[0];
|
||||||
|
|
||||||
|
if (n < 0) {
|
||||||
|
portCharPrint('-');
|
||||||
|
n = -n;
|
||||||
|
}
|
||||||
|
opcodes_print_num_r(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -100,6 +97,6 @@ void opcodes_print_paddr(void) {
|
||||||
|
|
||||||
void opcodes_print_ret(void) {
|
void opcodes_print_ret(void) {
|
||||||
__state.pc += zsciiPrint(__state.pc, 0);
|
__state.pc += zsciiPrint(__state.pc, 0);
|
||||||
portCharsPrint("\n", 1);
|
portCharPrint('\n');
|
||||||
interpreterDoReturn(1);
|
interpreterDoReturn(1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,97 +26,22 @@
|
||||||
#include "state.h"
|
#include "state.h"
|
||||||
#include "portme.h"
|
#include "portme.h"
|
||||||
#include "story.h"
|
#include "story.h"
|
||||||
#include "memory.h"
|
#include "opcodes.h"
|
||||||
|
|
||||||
|
|
||||||
void opcodes_save(void) {
|
void opcodes_save(void) {
|
||||||
uint32_t f;
|
interpreterDoBranch(portFileSave() ? 1 : 0);
|
||||||
bool ok;
|
|
||||||
uint16_t i;
|
|
||||||
uint8_t *b;
|
|
||||||
|
|
||||||
ok = portFileWriteOpen(&f, "save.dat");
|
|
||||||
|
|
||||||
// Write out PC.
|
|
||||||
b = (uint8_t *)&__state.pc;
|
|
||||||
ok &= portFileByteWrite(&f, b[0]);
|
|
||||||
ok &= portFileByteWrite(&f, b[1]);
|
|
||||||
ok &= portFileByteWrite(&f, b[2]);
|
|
||||||
ok &= portFileByteWrite(&f, b[3]);
|
|
||||||
|
|
||||||
// Write out SP.
|
|
||||||
b = (uint8_t *)&__state.sp;
|
|
||||||
ok &= portFileByteWrite(&f, b[0]);
|
|
||||||
ok &= portFileByteWrite(&f, b[1]);
|
|
||||||
|
|
||||||
// Write out BP.
|
|
||||||
b = (uint8_t *)&__state.sp;
|
|
||||||
ok &= portFileByteWrite(&f, b[0]);
|
|
||||||
ok &= portFileByteWrite(&f, b[1]);
|
|
||||||
|
|
||||||
// Write out dynamic memory.
|
|
||||||
for (i=0; i<storyStaticMemoryBaseAddress(); i++) {
|
|
||||||
ok &= portFileByteWrite(&f, ZPEEK(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write out stack.
|
|
||||||
for (i=0; i<__state.sp; i++) {
|
|
||||||
b = (uint8_t *)&__state.stack[i];
|
|
||||||
ok &= portFileByteWrite(&f, b[0]);
|
|
||||||
ok &= portFileByteWrite(&f, b[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
portFileClose(&f);
|
|
||||||
|
|
||||||
interpreterDoBranch(ok ? 1 : 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void opcodes_restart(void) {
|
void opcodes_restart(void) {
|
||||||
stateReset();
|
stateReset();
|
||||||
portStoryLoad();
|
portStoryLoad();
|
||||||
|
opcodesSetup();
|
||||||
storySetup();
|
storySetup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void opcodes_restore(void) {
|
void opcodes_restore(void) {
|
||||||
uint32_t f;
|
interpreterDoBranch(portFileRestore() ? 1 : 0);
|
||||||
bool ok;
|
|
||||||
uint16_t i;
|
|
||||||
uint8_t *b;
|
|
||||||
|
|
||||||
ok = portFileReadOpen(&f, "save.dat");
|
|
||||||
|
|
||||||
// Read PC.
|
|
||||||
b = (uint8_t *)&__state.pc;
|
|
||||||
b[0] = portFileByteRead(&f);
|
|
||||||
b[1] = portFileByteRead(&f);
|
|
||||||
b[2] = portFileByteRead(&f);
|
|
||||||
b[3] = portFileByteRead(&f);
|
|
||||||
|
|
||||||
// Read SP.
|
|
||||||
b = (uint8_t *)&__state.sp;
|
|
||||||
b[0] = portFileByteRead(&f);
|
|
||||||
b[1] = portFileByteRead(&f);
|
|
||||||
|
|
||||||
// Read BP.
|
|
||||||
b = (uint8_t *)&__state.bp;
|
|
||||||
b[0] = portFileByteRead(&f);
|
|
||||||
b[1] = portFileByteRead(&f);
|
|
||||||
|
|
||||||
// Read dynamic memory.
|
|
||||||
for (i=0; i<storyStaticMemoryBaseAddress(); i++) {
|
|
||||||
ZPOKE(i, portFileByteRead(&f));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read stack.
|
|
||||||
for (i=0; i<__state.sp; i++) {
|
|
||||||
b = (uint8_t *)&__state.stack[i];
|
|
||||||
b[0] = portFileByteRead(&f);
|
|
||||||
b[1] = portFileByteRead(&f);
|
|
||||||
}
|
|
||||||
|
|
||||||
portFileClose(&f);
|
|
||||||
|
|
||||||
interpreterDoBranch(ok ? 1 : 0);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,7 +94,7 @@ void opcodesBuiltInitialTable(void) {
|
||||||
OP(140, jump);
|
OP(140, jump);
|
||||||
OP(141, print_paddr);
|
OP(141, print_paddr);
|
||||||
OP(142, load);
|
OP(142, load);
|
||||||
mOP(143, not);
|
OP(143, not);
|
||||||
|
|
||||||
// 0-operand instructions...
|
// 0-operand instructions...
|
||||||
OP(176, rtrue);
|
OP(176, rtrue);
|
||||||
|
@ -106,7 +106,7 @@ void opcodesBuiltInitialTable(void) {
|
||||||
OP(182, restore);
|
OP(182, restore);
|
||||||
OP(183, restart);
|
OP(183, restart);
|
||||||
OP(184, ret_popped);
|
OP(184, ret_popped);
|
||||||
mOP(185, pop);
|
OP(185, pop);
|
||||||
OP(186, quit);
|
OP(186, quit);
|
||||||
OP(187, new_line);
|
OP(187, new_line);
|
||||||
|
|
||||||
|
|
89
src/portme.c
89
src/portme.c
|
@ -28,8 +28,12 @@
|
||||||
|
|
||||||
#include "portme.h"
|
#include "portme.h"
|
||||||
#include "story.h"
|
#include "story.h"
|
||||||
|
#include "memory.h"
|
||||||
|
#include "state.h"
|
||||||
|
#include "interpreter.h"
|
||||||
|
|
||||||
#include "zork1.h"
|
#include "zork1.h"
|
||||||
|
//#include "czech.z3.h"
|
||||||
|
|
||||||
|
|
||||||
// The F256 has 512k of RAM. We use everything except the lower 64k.
|
// The F256 has 512k of RAM. We use everything except the lower 64k.
|
||||||
|
@ -46,11 +50,9 @@ void portByteSet(uint16_t address, uint8_t value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void portCharsPrint(char *chars, uint16_t len) {
|
void portCharPrint(char c) {
|
||||||
uint16_t x;
|
printf("%c", c);
|
||||||
for (x=0; x<len; x++) {
|
fflush(stdout);
|
||||||
printf("%c", chars[x]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -67,28 +69,67 @@ void portDie(char *fmt, ...) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void portFileClose(uint32_t *handle) {
|
bool portFileRestore(void) {
|
||||||
|
|
||||||
|
FILE *in;
|
||||||
|
bool ok = false;
|
||||||
|
|
||||||
|
in = fopen("save.dat", "rb");
|
||||||
|
if (in) {
|
||||||
|
ok = true;
|
||||||
|
|
||||||
|
// Read in PC.
|
||||||
|
ok &= (fread(&__state.pc, sizeof(__state.pc), 1, in) == 1);
|
||||||
|
// Read in SP.
|
||||||
|
ok &= (fread(&__state.sp, sizeof(__state.sp), 1, in) == 1);
|
||||||
|
// Read in BP.
|
||||||
|
ok &= (fread(&__state.bp, sizeof(__state.bp), 1, in) == 1);
|
||||||
|
// Read in dynamic game RAM.
|
||||||
|
ok &= (fread(_RAM, storyStaticMemoryBaseAddress(), 1, in) == 1);
|
||||||
|
// Read in stack.
|
||||||
|
ok &= (fread(__state.stack, sizeof(__state.stack[0]), __state.sp, in) == __state.sp);
|
||||||
|
|
||||||
|
fclose(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
byte portFileByteRead(uint32_t *handle) {
|
bool portFileSave(void) {
|
||||||
return 0;
|
FILE *out;
|
||||||
|
bool ok = false;
|
||||||
|
|
||||||
|
out = fopen("save.dat", "wb");
|
||||||
|
if (out) {
|
||||||
|
ok = true;
|
||||||
|
|
||||||
|
// Write out PC.
|
||||||
|
ok &= (fwrite(&__state.pc, sizeof(__state.pc), 1, out) == 1);
|
||||||
|
// Write out SP.
|
||||||
|
ok &= (fwrite(&__state.sp, sizeof(__state.sp), 1, out) == 1);
|
||||||
|
// Write out BP.
|
||||||
|
ok &= (fwrite(&__state.bp, sizeof(__state.bp), 1, out) == 1);
|
||||||
|
// Write out dynamic game RAM.
|
||||||
|
ok &= (fwrite(_RAM, storyStaticMemoryBaseAddress(), 1, out) == 1);
|
||||||
|
// Write out stack.
|
||||||
|
ok &= (fwrite(__state.stack, sizeof(__state.stack[0]), __state.sp, out) == __state.sp);
|
||||||
|
|
||||||
|
fclose(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool portFileByteWrite(uint32_t *handle, byte value) {
|
void portInput(uint32_t ramAddr, uint8_t length) {
|
||||||
return false;
|
char input[256];
|
||||||
}
|
uint8_t i;
|
||||||
|
|
||||||
|
if (!fgets(input, length, stdin))
|
||||||
|
portDie("EOF or error on stdin during read");
|
||||||
|
|
||||||
bool portFileReadOpen(uint32_t *handle, char *name) {
|
for (i=0; i<length; i++) _RAM[ramAddr] = input[i];
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool portFileWriteOpen(uint32_t *handle, char *name) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -104,6 +145,7 @@ void portStoryLoad(void) {
|
||||||
|
|
||||||
// For now, we just copy an embedded Zork 1 into RAM.
|
// For now, we just copy an embedded Zork 1 into RAM.
|
||||||
memcpy(_RAM, zork1, zork1_len);
|
memcpy(_RAM, zork1, zork1_len);
|
||||||
|
//memcpy(_RAM, czech_z3, czech_z3_len);
|
||||||
|
|
||||||
// Later, we probably want to see if the user has a memory expansion
|
// 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
|
// installed. If they do, we can use it and then use the lower memory
|
||||||
|
@ -128,3 +170,14 @@ void portWordSet(uint16_t address, uint16_t value) {
|
||||||
_RAM[address + 1] = value & 0xff;
|
_RAM[address + 1] = value & 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
|
||||||
|
stateReset();
|
||||||
|
portStoryLoad();
|
||||||
|
opcodesSetup();
|
||||||
|
storySetup();
|
||||||
|
interpreterRun();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -21,9 +21,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "state.h"
|
#include "state.h"
|
||||||
|
#include "lib.h"
|
||||||
|
|
||||||
|
|
||||||
stateT __state;
|
stateT __state;
|
||||||
|
@ -31,5 +30,5 @@ stateT __state;
|
||||||
|
|
||||||
void stateReset(void) {
|
void stateReset(void) {
|
||||||
// Zero out all state data.
|
// Zero out all state data.
|
||||||
memset(&__state, 0, sizeof(stateT));
|
libMemSet((byte *)&__state, 0, sizeof(stateT));
|
||||||
}
|
}
|
||||||
|
|
33
src/story.c
33
src/story.c
|
@ -26,21 +26,26 @@
|
||||||
|
|
||||||
|
|
||||||
uint32_t storyLength() {
|
uint32_t storyLength() {
|
||||||
uint32_t m = (uint32_t)portWordGet(0x1a);
|
uint32_t m = (uint32_t)storyFileSize();
|
||||||
|
|
||||||
switch (storyVersion()) {
|
if (m > 0) {
|
||||||
case 1:
|
switch (storyVersion()) {
|
||||||
case 2:
|
case 1:
|
||||||
case 3:
|
case 2:
|
||||||
m *= 2;
|
case 3:
|
||||||
break;
|
m *= 2;
|
||||||
case 4:
|
break;
|
||||||
case 5:
|
case 4:
|
||||||
m *= 4;
|
case 5:
|
||||||
break;
|
m *= 4;
|
||||||
case 6:
|
break;
|
||||||
m *= 8;
|
case 6:
|
||||||
break;
|
m *= 8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Some old stories do not have the size in the header.
|
||||||
|
//***TODO***
|
||||||
}
|
}
|
||||||
|
|
||||||
return m;
|
return m;
|
||||||
|
|
|
@ -30,13 +30,13 @@
|
||||||
|
|
||||||
|
|
||||||
uint32_t variableAddressGlobal(uint16_t var) {
|
uint32_t variableAddressGlobal(uint16_t var) {
|
||||||
return storyGlobalVariableTableAddress() + ((var - 0x10) * 2);
|
return storyGlobalVariableTableAddress() + ((var - 16) * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint16_t variableLoad(uint16_t var) {
|
uint16_t variableLoad(uint16_t var) {
|
||||||
// Is it on the stack?
|
// Is it on the stack?
|
||||||
if (var < 16) return __state.stack[variableAddress(var, 0)];
|
if (var <= 16) return __state.stack[variableAddress(var, 0)];
|
||||||
// Nope, global.
|
// Nope, global.
|
||||||
return ZPEEKW(variableAddressGlobal(var));
|
return ZPEEKW(variableAddressGlobal(var));
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ uint16_t variableLoad(uint16_t var) {
|
||||||
void variableStore(uint16_t var, uint16_t value) {
|
void variableStore(uint16_t var, uint16_t value) {
|
||||||
uint32_t addr;
|
uint32_t addr;
|
||||||
|
|
||||||
if (var < 16) {
|
if (var <= 16) {
|
||||||
// On stack.
|
// On stack.
|
||||||
addr = variableAddress(var, 1);
|
addr = variableAddress(var, 1);
|
||||||
__state.stack[addr] = value;
|
__state.stack[addr] = value;
|
||||||
|
@ -60,14 +60,18 @@ void variableStore(uint16_t var, uint16_t value) {
|
||||||
uint8_t variableAddress(uint8_t var, bool writing) {
|
uint8_t variableAddress(uint8_t var, bool writing) {
|
||||||
uint16_t numLocals;
|
uint16_t numLocals;
|
||||||
|
|
||||||
if (var == 0) { // top of stack
|
// Top of stack.
|
||||||
|
if (var == 0) {
|
||||||
if (writing) {
|
if (writing) {
|
||||||
|
|
||||||
if (__state.sp >= sizeof(__state.stack)) portDie(MSG_INT_STACK_OVERFLOW);
|
if (__state.sp >= sizeof(__state.stack)) portDie(MSG_INT_STACK_OVERFLOW);
|
||||||
#ifdef DEBUGGING
|
#ifdef DEBUGGING
|
||||||
printf("Push stack\n");
|
printf("Push stack\n");
|
||||||
#endif
|
#endif
|
||||||
return __state.sp++;
|
return __state.sp++;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (__state.sp == 0) portDie(MSG_INT_STACK_UNDERFLOW);
|
if (__state.sp == 0) portDie(MSG_INT_STACK_UNDERFLOW);
|
||||||
numLocals = __state.bp ? __state.stack[__state.bp - 1] : 0;
|
numLocals = __state.bp ? __state.stack[__state.bp - 1] : 0;
|
||||||
if ((__state.bp + numLocals) >= sizeof(__state.stack)) portDie(MSG_INT_STACK_UNDERFLOW);
|
if ((__state.bp + numLocals) >= sizeof(__state.stack)) portDie(MSG_INT_STACK_UNDERFLOW);
|
||||||
|
@ -75,13 +79,15 @@ uint8_t variableAddress(uint8_t var, bool writing) {
|
||||||
printf("Pop stack\n");
|
printf("Pop stack\n");
|
||||||
#endif
|
#endif
|
||||||
return --__state.sp;
|
return --__state.sp;
|
||||||
|
|
||||||
} // writing
|
} // writing
|
||||||
} // var
|
} // var
|
||||||
|
|
||||||
if ((var >= 0x1) && (var <= 0xf)) { // Local var.
|
// Local var.
|
||||||
|
if ((var >= 0x1) && (var <= 0xf)) {
|
||||||
if (__state.stack[__state.bp - 1] <= (var - 1)) portDie(MSG_INT_REF_UNALLOCATED_LOCAL);
|
if (__state.stack[__state.bp - 1] <= (var - 1)) portDie(MSG_INT_REF_UNALLOCATED_LOCAL);
|
||||||
return __state.bp + (var - 1);
|
return __state.bp + (var - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return storyGlobalVariableTableAddress() + ((var - 0x10) * 2);
|
return variableAddressGlobal(var);
|
||||||
}
|
}
|
||||||
|
|
70
src/zscii.c
70
src/zscii.c
|
@ -29,8 +29,24 @@
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
|
||||||
|
|
||||||
uint32_t zsciiDecode(uint32_t zstr, bool abbr, char *buf, uint32_t *bufLenP) {
|
char zsciiDecodeChar(uint16_t z) {
|
||||||
uint32_t bufLen = *bufLenP;
|
char c = 0;
|
||||||
|
|
||||||
|
//***TODO*** V6+ has more codes.
|
||||||
|
|
||||||
|
if ((z >= 32) && (z <= 126)) {
|
||||||
|
c = z; // ASCII
|
||||||
|
} else if (z == 13) {
|
||||||
|
c = '\n';
|
||||||
|
} else if ((z >= 155) && (z <= 251)) {
|
||||||
|
c = '?'; //***TODO*** Extended ZSCII
|
||||||
|
}
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t zsciiPrint(uint32_t zstr, bool abbr) {
|
||||||
uint16_t code = 0;
|
uint16_t code = 0;
|
||||||
uint8_t alphabet = 0;
|
uint8_t alphabet = 0;
|
||||||
uint8_t useAbbrTable = 0;
|
uint8_t useAbbrTable = 0;
|
||||||
|
@ -71,10 +87,7 @@ uint32_t zsciiDecode(uint32_t zstr, bool abbr, char *buf, uint32_t *bufLenP) {
|
||||||
printVal = zsciiDecodeChar(zsciiCode);
|
printVal = zsciiDecodeChar(zsciiCode);
|
||||||
if (printVal) {
|
if (printVal) {
|
||||||
decodedChars++;
|
decodedChars++;
|
||||||
if (bufLen) {
|
portCharPrint(printVal);
|
||||||
*(buf++) = printVal;
|
|
||||||
bufLen--;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
alphabet = 0;
|
alphabet = 0;
|
||||||
useAbbrTable = 0;
|
useAbbrTable = 0;
|
||||||
|
@ -92,11 +105,7 @@ uint32_t zsciiDecode(uint32_t zstr, bool abbr, char *buf, uint32_t *bufLenP) {
|
||||||
abbrAddr = ZPEEKW(ptr);
|
abbrAddr = ZPEEKW(ptr);
|
||||||
ptr += 2;
|
ptr += 2;
|
||||||
|
|
||||||
abbrDecodedChars = bufLen;
|
decodedChars += zsciiPrint(abbrAddr * 2, true);
|
||||||
zsciiDecode(abbrAddr * 2, 1, buf, &abbrDecodedChars);
|
|
||||||
decodedChars += abbrDecodedChars;
|
|
||||||
buf += (bufLen < abbrDecodedChars) ? bufLen : abbrDecodedChars;
|
|
||||||
bufLen = (bufLen < abbrDecodedChars) ? 0 : (bufLen - abbrDecodedChars);
|
|
||||||
|
|
||||||
useAbbrTable = 0;
|
useAbbrTable = 0;
|
||||||
alphabet = 0; //***FIXME*** Version 3+ has no shift-lock but V1 needs it.
|
alphabet = 0; //***FIXME*** Version 3+ has no shift-lock but V1 needs it.
|
||||||
|
@ -148,10 +157,7 @@ uint32_t zsciiDecode(uint32_t zstr, bool abbr, char *buf, uint32_t *bufLenP) {
|
||||||
|
|
||||||
if (printVal) {
|
if (printVal) {
|
||||||
decodedChars++;
|
decodedChars++;
|
||||||
if (bufLen) {
|
portCharPrint(printVal);
|
||||||
*(buf++) = printVal;
|
|
||||||
bufLen--;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (alphabet && !newShift) alphabet = 0;
|
if (alphabet && !newShift) alphabet = 0;
|
||||||
|
@ -161,39 +167,5 @@ uint32_t zsciiDecode(uint32_t zstr, bool abbr, char *buf, uint32_t *bufLenP) {
|
||||||
// There is no NULL terminator, you look for a word with the top bit set.
|
// There is no NULL terminator, you look for a word with the top bit set.
|
||||||
} while ((code & (1 << 15)) == 0);
|
} while ((code & (1 << 15)) == 0);
|
||||||
|
|
||||||
*bufLenP = decodedChars;
|
|
||||||
|
|
||||||
return pc - zstr;
|
return pc - zstr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
char zsciiDecodeChar(uint16_t z) {
|
|
||||||
char c = 0;
|
|
||||||
|
|
||||||
//***TODO*** V6+ has more codes.
|
|
||||||
|
|
||||||
if ((z >= 32) && (z <= 126)) {
|
|
||||||
c = z; // ASCII
|
|
||||||
} else if (z == 13) {
|
|
||||||
c = '\n';
|
|
||||||
} else if ((z >= 155) && (z <= 251)) {
|
|
||||||
c = '?'; //***TODO*** Extended ZSCII
|
|
||||||
}
|
|
||||||
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
uint32_t zsciiPrint(uint32_t pc, bool abbr) {
|
|
||||||
uint32_t decodedChars = __memoryBufferLen;
|
|
||||||
uint32_t ret = zsciiDecode(pc, abbr, __memoryBuffer, &decodedChars);
|
|
||||||
|
|
||||||
if (decodedChars > __memoryBufferLen) {
|
|
||||||
memoryEnsureBuffer(decodedChars);
|
|
||||||
ret = zsciiDecode(pc, abbr, __memoryBuffer, &decodedChars);
|
|
||||||
}
|
|
||||||
|
|
||||||
portCharsPrint(__memoryBuffer, decodedChars);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue