Major code reorganization.
This commit is contained in:
parent
c93327084b
commit
af33bd6865
39 changed files with 1081 additions and 554 deletions
|
@ -7,16 +7,24 @@ set(HEADERS
|
|||
interpreter.h
|
||||
memory.h
|
||||
messages.h
|
||||
oc_0op.h
|
||||
oc_1op.h
|
||||
oc_2op.h
|
||||
oc_var_op.h
|
||||
oc_ext.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
|
||||
zork1.h
|
||||
)
|
||||
list(TRANSFORM HEADERS PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/include/")
|
||||
|
@ -25,15 +33,23 @@ set(SOURCE
|
|||
interpreter.c
|
||||
main.c
|
||||
memory.c
|
||||
oc_0op.c
|
||||
oc_1op.c
|
||||
oc_2op.c
|
||||
oc_var_op.c
|
||||
oc_ext.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
|
||||
portme.c
|
||||
state.c
|
||||
story.c
|
||||
variable.c
|
||||
zscii.c
|
||||
)
|
||||
list(TRANSFORM SOURCE PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/src/")
|
||||
|
||||
|
|
|
@ -25,7 +25,23 @@
|
|||
#define COMMON_H
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
#define DEBUGGING
|
||||
|
||||
|
||||
#ifdef DEBUGGING
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
|
||||
#define true 1
|
||||
#define false 0
|
||||
|
||||
|
||||
typedef unsigned char byte;
|
||||
typedef unsigned char bool;
|
||||
|
||||
|
||||
#endif // COMMON_H
|
||||
|
|
|
@ -25,25 +25,14 @@
|
|||
#define INTERPRETER_H
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include "common.h"
|
||||
#include "memory.h"
|
||||
|
||||
uint32_t interpreterDecodeZSCII(uint32_t zstr, bool abbr, char *buf, uint32_t *bufLenP);
|
||||
char interpreterDecodeZSCIIChar(uint16_t z);
|
||||
|
||||
void interpreterDoBranch(int32_t truth);
|
||||
void interpreterDoReturn(uint16_t r);
|
||||
uint32_t interpreterGetObjectPointer(uint16_t objectId);
|
||||
uint8_t interpreterGetObjectProperty(uint16_t objectId, uint32_t propertyId, uint8_t *size);
|
||||
uint32_t interpreterGlobalVariableAddress(uint16_t var);
|
||||
uint16_t interpreterLoadVariable(uint16_t var);
|
||||
bool interpreterParseOperand(uint8_t opType, uint8_t operandId);
|
||||
uint8_t interpreterParseVariableOperands(uint8_t index);
|
||||
void interpreterPrintChars(char *chars, uint16_t len);
|
||||
uint32_t interpreterPrintZSCII(uint32_t pc, bool abbr);
|
||||
void interpreterRun(void);
|
||||
void interpreterStoreVariable(uint16_t var, uint16_t value);
|
||||
uint8_t interpreterVariableAddress(uint8_t var, bool writing);
|
||||
|
||||
|
||||
#endif // INTERPRETER_H
|
||||
|
|
|
@ -25,40 +25,29 @@
|
|||
#define MEMORY_H
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include "common.h"
|
||||
#include "portme.h"
|
||||
|
||||
|
||||
#define MEMORY_ROUTINE 0
|
||||
#define MEMORY_PRINT 1
|
||||
|
||||
#define true 1
|
||||
#define false 0
|
||||
|
||||
// Memory access.
|
||||
#define PEEK(a) memoryByte(a)
|
||||
#define POKE(a,v) memorySetByte(a,v)
|
||||
#define PEEKW(a) memoryWord(a)
|
||||
#define POKEW(a,v) memorySetWord(a,v)
|
||||
|
||||
|
||||
typedef unsigned char byte;
|
||||
typedef unsigned char bool;
|
||||
#define ZPEEK(a) portByteGet(a)
|
||||
#define ZPOKE(a,v) portByteSet(a,v)
|
||||
#define ZPEEKW(a) portWordGet(a)
|
||||
#define ZPOKEW(a,v) portWordSet(a,v)
|
||||
|
||||
|
||||
extern char *__memoryBuffer;
|
||||
extern uint16_t __memoryBufferLen;
|
||||
|
||||
|
||||
uint8_t memoryByte(uint16_t address);
|
||||
void memoryEnsureBuffer(uint32_t newSize);
|
||||
void memoryLoadStory(void);
|
||||
void memorySetByte(uint16_t address, uint8_t value);
|
||||
void memorySetWord(uint16_t address, uint16_t value);
|
||||
void memoryShutdown(void);
|
||||
void memoryStartup(void);
|
||||
uint32_t memoryUnpackAddress(uint16_t address, uint8_t type);
|
||||
uint16_t memoryWord(uint16_t address);
|
||||
|
||||
|
||||
#endif // MEMORY_H
|
||||
|
|
35
include/object.h
Normal file
35
include/object.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* 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 OBJECT_H
|
||||
#define OBJECT_H
|
||||
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
||||
uint32_t objectPointerGet(uint16_t objectId);
|
||||
uint8_t objectPropertyGet(uint16_t objectId, uint32_t propertyId, uint8_t *size);
|
||||
|
||||
|
||||
#endif // OBJECT_H
|
35
include/oc_call.h
Normal file
35
include/oc_call.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* 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 OC_CALL_H
|
||||
#define OC_CALL_H
|
||||
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
||||
void opcodes_call(void);
|
||||
void opcodes_ret(void);
|
||||
|
||||
|
||||
#endif // OC_CALL_H
|
|
@ -21,15 +21,16 @@
|
|||
*/
|
||||
|
||||
|
||||
#ifndef OC_1OP_H
|
||||
#define OC_1OP_H
|
||||
#ifndef OC_COMPARE_H
|
||||
#define OC_COMPARE_H
|
||||
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
||||
void opcodes_je(void);
|
||||
void opcodes_jump(void);
|
||||
void opcodes_jz(void);
|
||||
void opcodes_ret(void);
|
||||
|
||||
#endif // OC_1OP_H
|
||||
|
||||
#endif // OC_COMPARE_H
|
31
include/oc_input.h
Normal file
31
include/oc_input.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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 OC_INPUT_H
|
||||
#define OC_INPUT_H
|
||||
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
||||
#endif // OC_INPUT_H
|
35
include/oc_math.h
Normal file
35
include/oc_math.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* 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 OC_MATH_H
|
||||
#define OC_MATH_H
|
||||
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
||||
void opcodes_add(void);
|
||||
void opcodes_sub(void);
|
||||
|
||||
|
||||
#endif // OC_MATH_H
|
36
include/oc_memory.h
Normal file
36
include/oc_memory.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 OC_MEMORY_H
|
||||
#define OC_MEMORY_H
|
||||
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
||||
void opcodes_loadw(void);
|
||||
void opcodes_store(void);
|
||||
void opcodes_storew(void);
|
||||
|
||||
|
||||
#endif // OC_MEMORY_H
|
|
@ -21,11 +21,11 @@
|
|||
*/
|
||||
|
||||
|
||||
#ifndef OC_EXT_H
|
||||
#define OC_EXT_H
|
||||
#ifndef OC_MISC_H
|
||||
#define OC_MISC_H
|
||||
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
||||
#endif // OC_EXT_H
|
||||
#endif // OC_MISC_H
|
|
@ -21,16 +21,15 @@
|
|||
*/
|
||||
|
||||
|
||||
#ifndef OC_VAR_OP_H
|
||||
#define OC_VAR_OP_H
|
||||
#ifndef OC_OBJECT_H
|
||||
#define OC_OBJECT_H
|
||||
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
||||
void opcodes_call(void);
|
||||
void opcodes_put_prop(void);
|
||||
void opcodes_storew(void);
|
||||
void opcodes_test_attr(void);
|
||||
|
||||
|
||||
#endif // OC_VAR_OP_H
|
||||
#endif // OC_OBJECT_H
|
|
@ -21,8 +21,8 @@
|
|||
*/
|
||||
|
||||
|
||||
#ifndef OC_0OP_H
|
||||
#define OC_0OP_H
|
||||
#ifndef OC_OUTPUT_H
|
||||
#define OC_OUTPUT_H
|
||||
|
||||
|
||||
#include "common.h"
|
||||
|
@ -32,4 +32,4 @@ void opcodes_new_line(void);
|
|||
void opcodes_print(void);
|
||||
|
||||
|
||||
#endif // OC_0OP_H
|
||||
#endif // OC_OUTPUT_H
|
31
include/oc_save.h
Normal file
31
include/oc_save.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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 OC_SAVE_H
|
||||
#define OC_SAVE_H
|
||||
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
||||
#endif // OC_SAVE_H
|
31
include/oc_window.h
Normal file
31
include/oc_window.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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 OC_WINDOW_H
|
||||
#define OC_WINDOW_H
|
||||
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
||||
#endif // OC_WINDOW_H
|
|
@ -25,13 +25,16 @@
|
|||
#define PORTME_H
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
||||
void portDie(char *fmt, ...);
|
||||
void portPrintChars(char *chars, uint16_t len);
|
||||
uint8_t portByteGet(uint16_t address);
|
||||
void portByteSet(uint16_t address, uint8_t value);
|
||||
void portDie(char *fmt, ...);
|
||||
void portPrintChars(char *chars, uint16_t len);
|
||||
void portStoryLoad(void);
|
||||
uint16_t portWordGet(uint16_t address);
|
||||
void portWordSet(uint16_t address, uint16_t value);
|
||||
|
||||
|
||||
#endif // PORTME_H
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
|
||||
|
||||
#include "common.h"
|
||||
#include "memory.h"
|
||||
#include "opcodes.h"
|
||||
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
|
||||
#include "common.h"
|
||||
#include "memory.h"
|
||||
#include "portme.h"
|
||||
|
||||
|
||||
#define STORY_STATUS_SCORE_TURNS 0
|
||||
|
@ -74,46 +74,47 @@
|
|||
|
||||
#define STORY_FLAG_3_USE_TRANSPARENCY (1 << 0)
|
||||
|
||||
#define storyVersion() memoryByte(0x0)
|
||||
#define storyFlags() memoryByte(STORY_FLAG_V3)
|
||||
#define storyHightMemory() memoryWord(0x4)
|
||||
#define storyInitialPC() memoryWord(0x6) // V1-5
|
||||
#define storyInitialPackedPC() memoryUnpackAddress(memoryWord(0x6), MEMORY_ROUTINE) // V6
|
||||
#define storyDictionaryAddress() memoryWord(0x8)
|
||||
#define storyObjectTableAddress() memoryWord(0xa)
|
||||
#define storyGlobalVariableTableAddress() memoryWord(0xc)
|
||||
#define storyStaticMemoryBaseAddress() memoryWord(0xe)
|
||||
#define storyFlags2() memoryWord(0x10)
|
||||
#define storyAbbreviationTableAddress() memoryWord(0x18)
|
||||
#define storyChecksum() memoryWord(0x1c)
|
||||
#define storyInterpreterNumber() memoryByte(0x1e)
|
||||
#define storyInterpreterVersion() memoryByte(0x1f)
|
||||
#define storyScreenHeightLines() memoryByte(0x20)
|
||||
#define storyScreenWidthCharacters() memoryByte(0x21)
|
||||
#define storyScreenHeightUnits() memoryWord(0x22)
|
||||
#define storyScreenWidthUnits() memoryWord(0x24)
|
||||
#define storyFontHeightUnits() (storyVersion() == 5 ? memoryByte(0x27) ? memoryByte(0x26)) // WTF Infocom?
|
||||
#define storyFontWidthUnits() (storyVersion() == 5 ? memoryByte(0x26) ? memoryByte(0x27))
|
||||
#define storyRoutinesOffset() memoryWord(0x28)
|
||||
#define storyStringsOffset() memoryWord(0x2a)
|
||||
#define storyDefaultBackgroundColor() memoryByte(0x2c)
|
||||
#define storyDefaultForegroundColor() memoryByte(0x2d)
|
||||
#define storyTerminatingCharactersTableAddress() memoryWord(0x2e)
|
||||
#define storyWidthInPixelsToOutputStream3() memoryByte(0x30)
|
||||
#define storyStandardRevisionNumber() memoryByte(0x32)
|
||||
#define storyAlphabetTableAddress() memoryWord(0x34)
|
||||
#define storyHeaderExtensionTableAddress() memoryWord(0x36)
|
||||
#define storyVersion() portByteGet(0x0)
|
||||
#define storyFlags() portByteGet(STORY_FLAG_V3)
|
||||
#define storyHightMemory() portWordGet(0x4)
|
||||
#define storyInitialPC() portWordGet(0x6) // V1-5
|
||||
#define storyInitialPackedPC() memoryUnpackAddress(portWordGet(0x6), MEMORY_ROUTINE) // V6
|
||||
#define storyDictionaryAddress() portWordGet(0x8)
|
||||
#define storyObjectTableAddress() portWordGet(0xa)
|
||||
#define storyGlobalVariableTableAddress() portWordGet(0xc)
|
||||
#define storyStaticMemoryBaseAddress() portWordGet(0xe)
|
||||
#define storyFlags2() portWordGet(0x10)
|
||||
#define storyAbbreviationTableAddress() portWordGet(0x18)
|
||||
#define storyChecksum() portWordGet(0x1c)
|
||||
#define storyInterpreterNumber() portByteGet(0x1e)
|
||||
#define storyInterpreterVersion() portByteGet(0x1f)
|
||||
#define storyScreenHeightLines() portByteGet(0x20)
|
||||
#define storyScreenWidthCharacters() portByteGet(0x21)
|
||||
#define storyScreenHeightUnits() portWordGet(0x22)
|
||||
#define storyScreenWidthUnits() portWordGet(0x24)
|
||||
#define storyFontHeightUnits() (storyVersion() == 5 ? portByteGet(0x27) ? portByteGet(0x26)) // WTF Infocom?
|
||||
#define storyFontWidthUnits() (storyVersion() == 5 ? portByteGet(0x26) ? portByteGet(0x27))
|
||||
#define storyRoutinesOffset() portWordGet(0x28)
|
||||
#define storyStringsOffset() portWordGet(0x2a)
|
||||
#define storyDefaultBackgroundColor() portByteGet(0x2c)
|
||||
#define storyDefaultForegroundColor() portByteGet(0x2d)
|
||||
#define storyTerminatingCharactersTableAddress() portWordGet(0x2e)
|
||||
#define storyWidthInPixelsToOutputStream3() portByteGet(0x30)
|
||||
#define storyStandardRevisionNumber() portByteGet(0x32)
|
||||
#define storyAlphabetTableAddress() portWordGet(0x34)
|
||||
#define storyHeaderExtensionTableAddress() portWordGet(0x36)
|
||||
|
||||
#define storyHXWordsInTable() memoryWord(storyHeaderExtensionTableAddress())
|
||||
#define storyHXMouseXClick() memoryWord(storyHeaderExtensionTableAddress() + 2)
|
||||
#define storyHXMouseYClick() memoryWord(storyHeaderExtensionTableAddress() + 4)
|
||||
#define storyHXUnicodeTranslationTableAddress() memoryWord(storyHeaderExtensionTableAddress() + 6)
|
||||
#define storyHXFlags3() memoryWord(storyHeaderExtensionTableAddress() + 8)
|
||||
#define storyHXTrueDefaultForegroundColor() memoryWord(storyHeaderExtensionTableAddress() + 10)
|
||||
#define storyHXTrueDefaultBackgroundColor() memoryWord(storyHeaderExtensionTableAddress() + 12)
|
||||
#define storyHXWordsInTable() portWordGet(storyHeaderExtensionTableAddress())
|
||||
#define storyHXMouseXClick() portWordGet(storyHeaderExtensionTableAddress() + 2)
|
||||
#define storyHXMouseYClick() portWordGet(storyHeaderExtensionTableAddress() + 4)
|
||||
#define storyHXUnicodeTranslationTableAddress() portWordGet(storyHeaderExtensionTableAddress() + 6)
|
||||
#define storyHXFlags3() portWordGet(storyHeaderExtensionTableAddress() + 8)
|
||||
#define storyHXTrueDefaultForegroundColor() portWordGet(storyHeaderExtensionTableAddress() + 10)
|
||||
#define storyHXTrueDefaultBackgroundColor() portWordGet(storyHeaderExtensionTableAddress() + 12)
|
||||
|
||||
|
||||
uint32_t storyLength();
|
||||
void storySetup(void);
|
||||
|
||||
|
||||
#endif // STORY_H
|
||||
|
|
37
include/variable.h
Normal file
37
include/variable.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* 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 VARIABLE_H
|
||||
#define VARIABLE_H
|
||||
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
||||
uint32_t variableAddressGlobal(uint16_t var);
|
||||
uint16_t variableLoad(uint16_t var);
|
||||
void variableStore(uint16_t var, uint16_t value);
|
||||
uint8_t variableAddress(uint8_t var, bool writing);
|
||||
|
||||
|
||||
#endif // VARIABLE_H
|
|
@ -21,19 +21,16 @@
|
|||
*/
|
||||
|
||||
|
||||
#ifndef OC_2OP_H
|
||||
#define OC_2OP_H
|
||||
#ifndef ZSCII_H
|
||||
#define ZSCII_H
|
||||
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
||||
void opcodes_add(void);
|
||||
void opcodes_je(void);
|
||||
void opcodes_loadw(void);
|
||||
void opcodes_store(void);
|
||||
void opcodes_sub(void);
|
||||
void opcodes_test_attr(void);
|
||||
uint32_t zsciiDecode(uint32_t zstr, bool abbr, char *buf, uint32_t *bufLenP);
|
||||
char zsciiDecodeChar(uint16_t z);
|
||||
uint32_t zsciiPrint(uint32_t pc, bool abbr);
|
||||
|
||||
|
||||
#endif // OC_2OP_H
|
||||
#endif // ZSCII_H
|
|
@ -26,172 +26,15 @@
|
|||
#include "messages.h"
|
||||
#include "story.h"
|
||||
#include "state.h"
|
||||
|
||||
#ifdef DEBUGGING
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
|
||||
uint32_t interpreterDecodeZSCII(uint32_t zstr, bool abbr, char *buf, uint32_t *bufLenP) {
|
||||
uint32_t bufLen = *bufLenP;
|
||||
uint16_t code = 0;
|
||||
uint8_t alphabet = 0;
|
||||
uint8_t useAbbrTable = 0;
|
||||
uint8_t zsciiCollector = 0;
|
||||
uint16_t zsciiCode = 0;
|
||||
uint32_t decodedChars = 0;
|
||||
uint32_t pc = zstr;
|
||||
char printVal = 0;
|
||||
uint32_t index;
|
||||
uint32_t ptr;
|
||||
uint16_t abbrAddr;
|
||||
uint32_t abbrDecodedChars;
|
||||
int8_t i;
|
||||
uint8_t ch;
|
||||
int16_t newShift;
|
||||
|
||||
do {
|
||||
code = PEEKW(pc);
|
||||
pc += 2;
|
||||
|
||||
// Characters are 5 bits each, packed three to a 16-bit word.
|
||||
for (i=10; i>=0; i-=5) {
|
||||
|
||||
newShift = 0;
|
||||
printVal = 0;
|
||||
ch = ((code >> i) & 0x1f);
|
||||
|
||||
if (zsciiCollector) {
|
||||
if (zsciiCollector == 2) {
|
||||
zsciiCode |= ((uint16_t)ch) << 5;
|
||||
} else {
|
||||
zsciiCode |= ((uint16_t)ch);
|
||||
}
|
||||
|
||||
zsciiCollector--;
|
||||
|
||||
if (!zsciiCollector) {
|
||||
printVal = interpreterDecodeZSCIIChar(zsciiCode);
|
||||
if (printVal) {
|
||||
decodedChars++;
|
||||
if (bufLen) {
|
||||
*(buf++) = printVal;
|
||||
bufLen--;
|
||||
}
|
||||
}
|
||||
alphabet = 0;
|
||||
useAbbrTable = 0;
|
||||
zsciiCode = 0;
|
||||
} // !zsciiCollector
|
||||
|
||||
continue;
|
||||
|
||||
} else if (useAbbrTable) { // zsciiCollector
|
||||
|
||||
if (abbr) portDie(MSG_INT_NO_ABBR);
|
||||
|
||||
index = ((32 * (((uint32_t)useAbbrTable) - 1)) + (uint32_t)ch);
|
||||
ptr = storyAbbreviationTableAddress() + (index * 2);
|
||||
abbrAddr = PEEKW(ptr);
|
||||
ptr += 2;
|
||||
|
||||
abbrDecodedChars = bufLen;
|
||||
interpreterDecodeZSCII(abbrAddr * 2, 1, buf, &abbrDecodedChars);
|
||||
decodedChars += abbrDecodedChars;
|
||||
buf += (bufLen < abbrDecodedChars) ? bufLen : abbrDecodedChars;
|
||||
bufLen = (bufLen < abbrDecodedChars) ? 0 : (bufLen - abbrDecodedChars);
|
||||
|
||||
useAbbrTable = 0;
|
||||
alphabet = 0; //***FIXME*** Version 3+ has no shift-lock but V1 needs it.
|
||||
|
||||
continue;
|
||||
|
||||
} // useAbbrTable
|
||||
|
||||
switch (ch) {
|
||||
case 0:
|
||||
printVal = ' ';
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (storyVersion() == 1) {
|
||||
printVal = '\n';
|
||||
} else {
|
||||
useAbbrTable = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
case 3:
|
||||
if (storyVersion() <= 2) {
|
||||
portDie(MSG_INT_V12_SHIFT);
|
||||
} else {
|
||||
useAbbrTable = ch;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
case 5:
|
||||
if (storyVersion() <= 2) {
|
||||
portDie(MSG_INT_V12_SHIFT_LOCK);
|
||||
} else {
|
||||
newShift = 1;
|
||||
alphabet = ch - 3;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if ((ch == 6) && (alphabet == 2)) {
|
||||
zsciiCollector = 2;
|
||||
} else {
|
||||
printVal = __state.alphabetTable[(alphabet * 26) + (ch - 6)];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (printVal) {
|
||||
decodedChars++;
|
||||
if (bufLen) {
|
||||
*(buf++) = printVal;
|
||||
bufLen--;
|
||||
}
|
||||
}
|
||||
|
||||
if (alphabet && !newShift) alphabet = 0;
|
||||
|
||||
} // for
|
||||
|
||||
// There is no NULL terminator, you look for a word with the top bit set.
|
||||
} while ((code & (1 << 15)) == 0);
|
||||
|
||||
*bufLenP = decodedChars;
|
||||
|
||||
return pc - zstr;
|
||||
}
|
||||
|
||||
|
||||
char interpreterDecodeZSCIIChar(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;
|
||||
}
|
||||
#include "variable.h"
|
||||
#include "memory.h"
|
||||
|
||||
|
||||
void interpreterDoBranch(int32_t truth) {
|
||||
uint8_t branch = PEEK(__state.pc++);
|
||||
uint8_t branch = ZPEEK(__state.pc++);
|
||||
int32_t farJump = (branch & (1 << 6)) == 0;
|
||||
int32_t onTruth = (branch & (1 << 7)) ? 1 : 0;
|
||||
uint8_t byte2 = farJump ? PEEK(__state.pc++) : 0;
|
||||
uint8_t byte2 = farJump ? ZPEEK(__state.pc++) : 0;
|
||||
int16_t offset;
|
||||
|
||||
if (onTruth == truth) {
|
||||
|
@ -241,70 +84,7 @@ void interpreterDoReturn(uint16_t r) {
|
|||
#endif
|
||||
|
||||
// Store the routine result.
|
||||
interpreterStoreVariable(storeId, r);
|
||||
}
|
||||
|
||||
|
||||
uint32_t interpreterGetObjectPointer(uint16_t objectId) {
|
||||
uint32_t ptr;
|
||||
|
||||
if (objectId == 0) portDie(MSG_INT_OBJECT0_REF);
|
||||
if ((storyVersion() <= 3) && (objectId > 255)) portDie(MSG_INT_OBJECT_BAD_ID);
|
||||
|
||||
ptr = storyObjectTableAddress();
|
||||
ptr += 31 * 2; // Skip properties defaults table.
|
||||
ptr += 9 * (objectId - 1); // Find object in table.
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
uint8_t interpreterGetObjectProperty(uint16_t objectId, uint32_t propertyId, uint8_t *size) {
|
||||
uint32_t ptr = interpreterGetObjectPointer(objectId);
|
||||
uint16_t addr;
|
||||
uint8_t info;
|
||||
uint16_t num;
|
||||
uint8_t s;
|
||||
|
||||
if (storyVersion() <= 3) {
|
||||
ptr += 7; // Skip to properties address field.
|
||||
addr = PEEKW(ptr);
|
||||
ptr = addr;
|
||||
ptr += PEEK(ptr) * 2 + 1; // Skip object name to start of properties.
|
||||
while (1) {
|
||||
info = PEEK(ptr++);
|
||||
num = (info & 0x1f); // 5 bits for property ID.
|
||||
s = ((info >> 5) & 0x7) + 1; // 3 bits for property size.
|
||||
|
||||
// These go in descending numeric order, and should fail the interpreter if missing.
|
||||
// We use 0xFFFFFFFF internally to mean "first property".
|
||||
if ((num == propertyId) || (propertyId == 0xFFFFFFFF)) { // found it?
|
||||
if (size) *size = s;
|
||||
return ptr;
|
||||
} else if (num < propertyId) // we're past it.
|
||||
break;
|
||||
|
||||
// Try the next property.
|
||||
ptr += s;
|
||||
}
|
||||
} else {
|
||||
portDie(MSG_UNIMPLEMENTED);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
uint32_t interpreterGlobalVariableAddress(uint16_t var) {
|
||||
return storyGlobalVariableTableAddress() + ((var - 0x10) * 2);
|
||||
}
|
||||
|
||||
|
||||
uint16_t interpreterLoadVariable(uint16_t var) {
|
||||
// Is it on the stack?
|
||||
if (var < 16) return __state.stack[interpreterVariableAddress(var, 0)];
|
||||
// Nope, global.
|
||||
return PEEKW(interpreterGlobalVariableAddress(var));
|
||||
variableStore(storeId, r);
|
||||
}
|
||||
|
||||
|
||||
|
@ -312,18 +92,18 @@ bool interpreterParseOperand(uint8_t opType, uint8_t operandId) {
|
|||
switch(opType) {
|
||||
// Large constant.
|
||||
case 0:
|
||||
__state.operands[operandId] = PEEKW(__state.pc);
|
||||
__state.operands[operandId] = ZPEEKW(__state.pc);
|
||||
__state.pc += 2;
|
||||
return true;
|
||||
|
||||
// Small constant.
|
||||
case 1:
|
||||
__state.operands[operandId] = PEEK(__state.pc++);
|
||||
__state.operands[operandId] = ZPEEK(__state.pc++);
|
||||
return true;
|
||||
|
||||
// Variable.
|
||||
case 2:
|
||||
__state.operands[operandId] = interpreterLoadVariable(PEEK(__state.pc++));
|
||||
__state.operands[operandId] = variableLoad(ZPEEK(__state.pc++));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -332,7 +112,7 @@ bool interpreterParseOperand(uint8_t opType, uint8_t operandId) {
|
|||
|
||||
|
||||
uint8_t interpreterParseVariableOperands(uint8_t index) {
|
||||
uint8_t operandTypes = PEEK(__state.pc++);
|
||||
uint8_t operandTypes = ZPEEK(__state.pc++);
|
||||
uint8_t shifter = 6;
|
||||
uint8_t i;
|
||||
uint8_t opType;
|
||||
|
@ -347,28 +127,6 @@ uint8_t interpreterParseVariableOperands(uint8_t index) {
|
|||
}
|
||||
|
||||
|
||||
void interpreterPrintChars(char *chars, uint16_t len) {
|
||||
//***TODO*** This is where we need to deal with windows and screen
|
||||
// splits and other stuff.
|
||||
portPrintChars(chars, len);
|
||||
}
|
||||
|
||||
|
||||
uint32_t interpreterPrintZSCII(uint32_t pc, bool abbr) {
|
||||
uint32_t decodedChars = __memoryBufferLen;
|
||||
uint32_t ret = interpreterDecodeZSCII(pc, abbr, __memoryBuffer, &decodedChars);
|
||||
|
||||
if (decodedChars > __memoryBufferLen) {
|
||||
memoryEnsureBuffer(decodedChars);
|
||||
ret = interpreterDecodeZSCII(pc, abbr, __memoryBuffer, &decodedChars);
|
||||
}
|
||||
|
||||
interpreterPrintChars(__memoryBuffer, decodedChars);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void interpreterRun(void) {
|
||||
uint8_t opcode;
|
||||
bool extended;
|
||||
|
@ -376,12 +134,12 @@ void interpreterRun(void) {
|
|||
bool eight;
|
||||
|
||||
while (__state.quit == 0) {
|
||||
opcode = PEEK(__state.pc++);
|
||||
opcode = ZPEEK(__state.pc++);
|
||||
extended = ((opcode == 190) && (storyVersion() >= 5)) ? true : false;
|
||||
|
||||
if (extended) {
|
||||
|
||||
opcode = PEEK(__state.pc++);
|
||||
opcode = ZPEEK(__state.pc++);
|
||||
if (opcode >= (sizeof(__state.extOpcodes) / sizeof(__state.extOpcodes[0]))) portDie(MSG_INT_INVALID_EXT_OPCODE);
|
||||
__state.operandCount = interpreterParseVariableOperands(0);
|
||||
op = __state.extOpcodes[opcode];
|
||||
|
@ -437,47 +195,3 @@ void interpreterRun(void) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void interpreterStoreVariable(uint16_t var, uint16_t value) {
|
||||
uint32_t addr;
|
||||
|
||||
if (var < 16) {
|
||||
// On stack.
|
||||
addr = interpreterVariableAddress(var, 1);
|
||||
__state.stack[addr] = value;
|
||||
} else {
|
||||
// Global.
|
||||
addr = interpreterGlobalVariableAddress(var);
|
||||
POKEW(addr, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint8_t interpreterVariableAddress(uint8_t var, bool writing) {
|
||||
uint16_t numLocals;
|
||||
|
||||
if (var == 0) { // top of stack
|
||||
if (writing) {
|
||||
if (__state.sp >= sizeof(__state.stack)) portDie(MSG_INT_STACK_OVERFLOW);
|
||||
#ifdef DEBUGGING
|
||||
printf("Push stack\n");
|
||||
#endif
|
||||
return __state.sp++;
|
||||
} else {
|
||||
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
|
||||
printf("Pop stack\n");
|
||||
#endif
|
||||
return --__state.sp;
|
||||
} // writing
|
||||
} // var
|
||||
|
||||
if ((var >= 0x1) && (var <= 0xf)) { // Local var.
|
||||
if (__state.stack[__state.bp - 1] <= (var - 1)) portDie(MSG_INT_REF_UNALLOCATED_LOCAL);
|
||||
return __state.bp + (var - 1);
|
||||
}
|
||||
|
||||
return storyGlobalVariableTableAddress() + ((var - 0x10) * 2);
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "opcodes.h"
|
||||
#include "state.h"
|
||||
#include "interpreter.h"
|
||||
#include "story.h"
|
||||
|
||||
|
||||
int main(void) {
|
||||
|
@ -48,7 +49,8 @@ int main(void) {
|
|||
memoryStartup();
|
||||
stateReset();
|
||||
opcodesSetup();
|
||||
memoryLoadStory();
|
||||
portStoryLoad();
|
||||
storySetup();
|
||||
interpreterRun();
|
||||
memoryShutdown();
|
||||
|
||||
|
|
81
src/memory.c
81
src/memory.c
|
@ -21,32 +21,19 @@
|
|||
*/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "memory.h"
|
||||
#include "story.h"
|
||||
#include "state.h"
|
||||
#include "portme.h"
|
||||
#include "messages.h"
|
||||
|
||||
#include "zork1.h"
|
||||
|
||||
|
||||
// Generic buffer for whatever.
|
||||
char *__memoryBuffer = 0;
|
||||
uint16_t __memoryBufferLen = 0;
|
||||
|
||||
|
||||
// The F256 has 512k of RAM. We use everything except the lower 64k.
|
||||
static uint8_t _RAM[1024 * (512 - 64)];
|
||||
|
||||
|
||||
uint8_t memoryByte(uint16_t address) {
|
||||
return _RAM[address];
|
||||
}
|
||||
|
||||
|
||||
void memoryEnsureBuffer(uint32_t newSize) {
|
||||
if (__memoryBufferLen >= newSize) return;
|
||||
free(__memoryBuffer);
|
||||
|
@ -58,65 +45,6 @@ void memoryEnsureBuffer(uint32_t newSize) {
|
|||
}
|
||||
|
||||
|
||||
void memoryLoadStory(void) {
|
||||
char *p;
|
||||
uint16_t i;
|
||||
|
||||
// For now, we just copy an embedded Zork 1 into RAM.
|
||||
memcpy(_RAM, zork1, zork1_len);
|
||||
|
||||
// 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.
|
||||
POKE(STORY_FLAG_V3, PEEK(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);
|
||||
|
||||
// V6+ this is the address of main(), not just a raw starting address.
|
||||
__state.pc = storyInitialPC();
|
||||
__state.sp = 0;
|
||||
|
||||
// Set up alphabet tables. ***TODO*** V5+ has alternate tables in header.
|
||||
p = __state.alphabetTable;
|
||||
for (i=0; i<26; i++) *(p++) = 'a' + i; // Alphabet A0
|
||||
for (i=0; i<26; i++) *(p++) = 'A' + i; // Alphabet A1
|
||||
// Alphabet A2
|
||||
*(p++) = 0;
|
||||
if (storyVersion() != 1) *(p++) = '\n';
|
||||
for (i=0; i<10; i++) *(p++) = '0' + i;
|
||||
*(p++) = '.';
|
||||
*(p++) = ',';
|
||||
*(p++) = '!';
|
||||
*(p++) = '?';
|
||||
*(p++) = '_';
|
||||
*(p++) = '#';
|
||||
*(p++) = '\'';
|
||||
*(p++) = '"';
|
||||
*(p++) = '/';
|
||||
*(p++) = '\\';
|
||||
if (storyVersion() == 1) *(p++) = '<';
|
||||
*(p++) = '-';
|
||||
*(p++) = ':';
|
||||
*(p++) = '(';
|
||||
*(p++) = ')';
|
||||
}
|
||||
|
||||
|
||||
void memorySetByte(uint16_t address, uint8_t value) {
|
||||
_RAM[address] = value;
|
||||
}
|
||||
|
||||
|
||||
void memorySetWord(uint16_t address, uint16_t value) {
|
||||
_RAM[address] = (value >> 8) & 0xff; // MSB first.
|
||||
_RAM[address + 1] = value & 0xff;
|
||||
}
|
||||
|
||||
|
||||
void memoryShutdown(void) {
|
||||
free(__memoryBuffer);
|
||||
__memoryBuffer = 0;
|
||||
|
@ -125,7 +53,7 @@ void memoryShutdown(void) {
|
|||
|
||||
|
||||
void memoryStartup(void) {
|
||||
memoryEnsureBuffer(512);
|
||||
memoryEnsureBuffer(1024);
|
||||
}
|
||||
|
||||
|
||||
|
@ -148,10 +76,5 @@ uint32_t memoryUnpackAddress(uint16_t address, uint8_t type) {
|
|||
return (uint32_t)address * 8;
|
||||
}
|
||||
|
||||
return ((uint16_t)_RAM[address] << 8) | ((uint16_t)_RAM[address + 1]);
|
||||
}
|
||||
|
||||
|
||||
uint16_t memoryWord(uint16_t address) {
|
||||
return ((uint16_t)_RAM[address] << 8) | ((uint16_t)_RAM[address + 1]);
|
||||
return ((uint16_t)ZPEEK(address) << 8) | ((uint16_t)ZPEEK(address + 1));
|
||||
}
|
||||
|
|
80
src/object.c
Normal file
80
src/object.c
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
#include "object.h"
|
||||
#include "story.h"
|
||||
#include "portme.h"
|
||||
#include "messages.h"
|
||||
#include "memory.h"
|
||||
|
||||
|
||||
uint32_t objectPointerGet(uint16_t objectId) {
|
||||
uint32_t ptr;
|
||||
|
||||
if (objectId == 0) portDie(MSG_INT_OBJECT0_REF);
|
||||
if ((storyVersion() <= 3) && (objectId > 255)) portDie(MSG_INT_OBJECT_BAD_ID);
|
||||
|
||||
ptr = storyObjectTableAddress();
|
||||
ptr += 31 * 2; // Skip properties defaults table.
|
||||
ptr += 9 * (objectId - 1); // Find object in table.
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
uint8_t objectPropertyGet(uint16_t objectId, uint32_t propertyId, uint8_t *size) {
|
||||
uint32_t ptr = objectPointerGet(objectId);
|
||||
uint16_t addr;
|
||||
uint8_t info;
|
||||
uint16_t num;
|
||||
uint8_t s;
|
||||
|
||||
if (storyVersion() <= 3) {
|
||||
ptr += 7; // Skip to properties address field.
|
||||
addr = ZPEEKW(ptr);
|
||||
ptr = addr;
|
||||
ptr += ZPEEK(ptr) * 2 + 1; // Skip object name to start of properties.
|
||||
while (1) {
|
||||
info = ZPEEK(ptr++);
|
||||
num = (info & 0x1f); // 5 bits for property ID.
|
||||
s = ((info >> 5) & 0x7) + 1; // 3 bits for property size.
|
||||
|
||||
// These go in descending numeric order, and should fail the interpreter if missing.
|
||||
// We use 0xFFFFFFFF internally to mean "first property".
|
||||
if ((num == propertyId) || (propertyId == 0xFFFFFFFF)) { // found it?
|
||||
if (size) *size = s;
|
||||
return ptr;
|
||||
} else if (num < propertyId) // we're past it.
|
||||
break;
|
||||
|
||||
// Try the next property.
|
||||
ptr += s;
|
||||
}
|
||||
} else {
|
||||
portDie(MSG_UNIMPLEMENTED);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -21,18 +21,19 @@
|
|||
*/
|
||||
|
||||
|
||||
#include "oc_var_op.h"
|
||||
#include "oc_call.h"
|
||||
#include "state.h"
|
||||
#include "memory.h"
|
||||
#include "interpreter.h"
|
||||
#include "messages.h"
|
||||
#include "portme.h"
|
||||
#include "interpreter.h"
|
||||
#include "story.h"
|
||||
#include "variable.h"
|
||||
#include "memory.h"
|
||||
|
||||
|
||||
void opcodes_call(void) {
|
||||
uint8_t args = __state.operandCount;
|
||||
uint8_t storeId = PEEK(__state.pc++);
|
||||
uint8_t storeId = ZPEEK(__state.pc++);
|
||||
uint32_t routine;
|
||||
uint8_t numLocals;
|
||||
int8_t i;
|
||||
|
@ -41,10 +42,10 @@ void opcodes_call(void) {
|
|||
|
||||
if ((args == 0) && (__state.operands[0] == 0)) {
|
||||
// Legal no-op; store 0 to return value and bounce.
|
||||
POKEW(interpreterVariableAddress(storeId, 1), 0);
|
||||
ZPOKEW(variableAddress(storeId, 1), 0);
|
||||
} else {
|
||||
routine = memoryUnpackAddress(__state.operands[0], MEMORY_ROUTINE);
|
||||
numLocals = PEEK(routine++);
|
||||
numLocals = ZPEEK(routine++);
|
||||
if (numLocals > 15) portDie(MSG_OP_VAR_TOO_MANY_LOCALS);
|
||||
|
||||
if (__state.sp + 5 + numLocals >= sizeof(__state.stack)) portDie(MSG_OP_VAR_STACK_OVERFLOW);
|
||||
|
@ -66,7 +67,7 @@ void opcodes_call(void) {
|
|||
__state.bp = __state.sp;
|
||||
|
||||
if (storyVersion() <= 4) {
|
||||
for (i=0; i<numLocals; i++, routine += 2) __state.stack[__state.sp++] = PEEKW(routine);
|
||||
for (i=0; i<numLocals; i++, routine += 2) __state.stack[__state.sp++] = ZPEEKW(routine);
|
||||
} else {
|
||||
for (i=0; i<numLocals; i++) __state.stack[__state.sp++] = 0;
|
||||
}
|
||||
|
@ -89,20 +90,6 @@ void opcodes_call(void) {
|
|||
}
|
||||
|
||||
|
||||
void opcodes_put_prop(void) {
|
||||
uint8_t size = 0;
|
||||
uint8_t ptr = interpreterGetObjectProperty(__state.operands[0], __state.operands[1], &size);
|
||||
|
||||
if (ptr == 0) portDie(MSG_OP_VAR_MISSING_PROPERTY);
|
||||
|
||||
if (size == 1) {
|
||||
POKE(ptr, (__state.operands[2] & 0xff));
|
||||
} else {
|
||||
POKEW(ptr, __state.operands[2]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void opcodes_storew(void) {
|
||||
POKEW(__state.operands[0] + (__state.operands[1] * 2), __state.operands[2]);
|
||||
void opcodes_ret(void) {
|
||||
interpreterDoReturn(__state.operands[0]);
|
||||
}
|
|
@ -21,11 +21,26 @@
|
|||
*/
|
||||
|
||||
|
||||
#include "oc_1op.h"
|
||||
#include "oc_compare.h"
|
||||
#include "state.h"
|
||||
#include "interpreter.h"
|
||||
|
||||
|
||||
void opcodes_je(void) {
|
||||
uint16_t a = __state.operands[0];
|
||||
int8_t i;
|
||||
|
||||
for (i=1; i<__state.operandCount; i++) {
|
||||
if (a == __state.operands[i]) {
|
||||
interpreterDoBranch(1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
interpreterDoBranch(0);
|
||||
}
|
||||
|
||||
|
||||
void opcodes_jump(void) {
|
||||
__state.pc = __state.pc + ((int16_t)__state.operands[0]) - 2;
|
||||
}
|
||||
|
@ -36,8 +51,3 @@ void opcodes_jz(void) {
|
|||
}
|
||||
|
||||
|
||||
void opcodes_ret(void) {
|
||||
interpreterDoReturn(__state.operands[0]);
|
||||
}
|
||||
|
||||
|
24
src/oc_input.c
Normal file
24
src/oc_input.c
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
#include "oc_input.h"
|
38
src/oc_math.c
Normal file
38
src/oc_math.c
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
#include "oc_math.h"
|
||||
#include "variable.h"
|
||||
#include "state.h"
|
||||
#include "memory.h"
|
||||
|
||||
|
||||
void opcodes_add(void) {
|
||||
variableStore(ZPEEK(__state.pc++), __state.operands[0] + __state.operands[1]);
|
||||
}
|
||||
|
||||
|
||||
void opcodes_sub(void) {
|
||||
variableStore(ZPEEK(__state.pc++), __state.operands[0] - __state.operands[1]);
|
||||
}
|
||||
|
43
src/oc_memory.c
Normal file
43
src/oc_memory.c
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
#include "oc_memory.h"
|
||||
#include "variable.h"
|
||||
#include "state.h"
|
||||
#include "memory.h"
|
||||
|
||||
|
||||
void opcodes_loadw(void) {
|
||||
uint16_t offset = __state.operands[0] + (__state.operands[1] * 2);
|
||||
variableStore(ZPEEK(__state.pc++), ZPEEKW(offset));
|
||||
}
|
||||
|
||||
|
||||
void opcodes_store(void) {
|
||||
variableStore((__state.operands[0] & 0xFF), __state.operands[1]);
|
||||
}
|
||||
|
||||
|
||||
void opcodes_storew(void) {
|
||||
ZPOKEW(__state.operands[0] + (__state.operands[1] * 2), __state.operands[2]);
|
||||
}
|
|
@ -21,4 +21,4 @@
|
|||
*/
|
||||
|
||||
|
||||
#include "oc_ext.h"
|
||||
#include "oc_misc.h"
|
|
@ -21,58 +21,37 @@
|
|||
*/
|
||||
|
||||
|
||||
#include "oc_2op.h"
|
||||
#include "oc_object.h"
|
||||
#include "interpreter.h"
|
||||
#include "state.h"
|
||||
#include "memory.h"
|
||||
#include "story.h"
|
||||
#include "portme.h"
|
||||
#include "messages.h"
|
||||
#include "object.h"
|
||||
|
||||
|
||||
void opcodes_add(void) {
|
||||
interpreterStoreVariable(PEEK(__state.pc++), __state.operands[0] + __state.operands[1]);
|
||||
}
|
||||
void opcodes_put_prop(void) {
|
||||
uint8_t size = 0;
|
||||
uint8_t ptr = objectPropertyGet(__state.operands[0], __state.operands[1], &size);
|
||||
|
||||
if (ptr == 0) portDie(MSG_OP_VAR_MISSING_PROPERTY);
|
||||
|
||||
void opcodes_je(void) {
|
||||
uint16_t a = __state.operands[0];
|
||||
int8_t i;
|
||||
|
||||
for (i=1; i<__state.operandCount; i++) {
|
||||
if (a == __state.operands[i]) {
|
||||
interpreterDoBranch(1);
|
||||
return;
|
||||
}
|
||||
if (size == 1) {
|
||||
ZPOKE(ptr, (__state.operands[2] & 0xff));
|
||||
} else {
|
||||
ZPOKEW(ptr, __state.operands[2]);
|
||||
}
|
||||
|
||||
interpreterDoBranch(0);
|
||||
}
|
||||
|
||||
|
||||
void opcodes_loadw(void) {
|
||||
uint16_t offset = __state.operands[0] + (__state.operands[1] * 2);
|
||||
interpreterStoreVariable(PEEK(__state.pc++), PEEKW(offset));
|
||||
}
|
||||
|
||||
|
||||
void opcodes_store(void) {
|
||||
interpreterStoreVariable((__state.operands[0] & 0xFF), __state.operands[1]);
|
||||
}
|
||||
|
||||
|
||||
void opcodes_sub(void) {
|
||||
interpreterStoreVariable(PEEK(__state.pc++), __state.operands[0] - __state.operands[1]);
|
||||
}
|
||||
|
||||
|
||||
void opcodes_test_attr(void) {
|
||||
uint32_t ptr = interpreterGetObjectPointer(__state.operands[0]);
|
||||
uint32_t ptr = objectPointerGet(__state.operands[0]);
|
||||
uint16_t attrId = __state.operands[1];
|
||||
|
||||
if (storyVersion() <= 3) {
|
||||
ptr += (attrId / 8);
|
||||
interpreterDoBranch((PEEK(ptr) & (0x80 >> (attrId & 7))) ? 1 : 0);
|
||||
interpreterDoBranch((ZPEEK(ptr) & (0x80 >> (attrId & 7))) ? 1 : 0);
|
||||
} else {
|
||||
portDie(MSG_UNIMPLEMENTED);
|
||||
}
|
|
@ -21,16 +21,17 @@
|
|||
*/
|
||||
|
||||
|
||||
#include "oc_0op.h"
|
||||
#include "interpreter.h"
|
||||
#include "oc_output.h"
|
||||
#include "state.h"
|
||||
#include "portme.h"
|
||||
#include "zscii.h"
|
||||
|
||||
|
||||
void opcodes_new_line(void) {
|
||||
interpreterPrintChars("\n", 1);
|
||||
portPrintChars("\n", 1);
|
||||
}
|
||||
|
||||
|
||||
void opcodes_print(void) {
|
||||
__state.pc += interpreterPrintZSCII(__state.pc, 0);
|
||||
__state.pc += zsciiPrint(__state.pc, 0);
|
||||
}
|
24
src/oc_save.c
Normal file
24
src/oc_save.c
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
#include "oc_save.h"
|
24
src/oc_window.c
Normal file
24
src/oc_window.c
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
#include "oc_window.h"
|
|
@ -25,11 +25,16 @@
|
|||
#include "story.h"
|
||||
#include "state.h"
|
||||
#include "opcodes.h"
|
||||
#include "oc_0op.h"
|
||||
#include "oc_1op.h"
|
||||
#include "oc_2op.h"
|
||||
#include "oc_var_op.h"
|
||||
#include "oc_ext.h"
|
||||
#include "oc_call.h"
|
||||
#include "oc_compare.h"
|
||||
#include "oc_input.h"
|
||||
#include "oc_math.h"
|
||||
#include "oc_memory.h"
|
||||
#include "oc_misc.h"
|
||||
#include "oc_object.h"
|
||||
#include "oc_output.h"
|
||||
#include "oc_save.h"
|
||||
#include "oc_window.h"
|
||||
|
||||
|
||||
// Macros to declare implemented opcodes.
|
||||
|
|
48
src/portme.c
48
src/portme.c
|
@ -24,8 +24,26 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "portme.h"
|
||||
#include "story.h"
|
||||
|
||||
#include "zork1.h"
|
||||
|
||||
|
||||
// The F256 has 512k of RAM. We use everything except the lower 64k.
|
||||
static uint8_t _RAM[1024 * (512 - 64)];
|
||||
|
||||
|
||||
uint8_t portByteGet(uint16_t address) {
|
||||
return _RAM[address];
|
||||
}
|
||||
|
||||
|
||||
void portByteSet(uint16_t address, uint8_t value) {
|
||||
_RAM[address] = value;
|
||||
}
|
||||
|
||||
|
||||
void portDie(char *fmt, ...) {
|
||||
|
@ -47,3 +65,33 @@ void portPrintChars(char *chars, uint16_t len) {
|
|||
printf("%c", chars[x]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void portStoryLoad(void) {
|
||||
|
||||
// For now, we just copy an embedded Zork 1 into RAM.
|
||||
memcpy(_RAM, zork1, zork1_len);
|
||||
|
||||
// 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 ((uint16_t)_RAM[address] << 8) | ((uint16_t)_RAM[address + 1]);
|
||||
}
|
||||
|
||||
|
||||
void portWordSet(uint16_t address, uint16_t value) {
|
||||
_RAM[address] = (value >> 8) & 0xff; // MSB first.
|
||||
_RAM[address + 1] = value & 0xff;
|
||||
}
|
||||
|
||||
|
|
60
src/story.c
60
src/story.c
|
@ -1,8 +1,32 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
#include "story.h"
|
||||
#include "state.h"
|
||||
|
||||
|
||||
uint32_t storyLength() {
|
||||
uint32_t m = (uint32_t)memoryWord(0x1a);
|
||||
uint32_t m = (uint32_t)portWordGet(0x1a);
|
||||
|
||||
switch (storyVersion()) {
|
||||
case 1:
|
||||
|
@ -21,3 +45,37 @@ uint32_t storyLength() {
|
|||
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
void storySetup(void) {
|
||||
char *p;
|
||||
uint16_t i;
|
||||
|
||||
// V6+ this is the address of main(), not just a raw starting address.
|
||||
__state.pc = storyInitialPC();
|
||||
__state.sp = 0;
|
||||
|
||||
// Set up alphabet tables. ***TODO*** V5+ has alternate tables in header.
|
||||
p = __state.alphabetTable;
|
||||
for (i=0; i<26; i++) *(p++) = 'a' + i; // Alphabet A0
|
||||
for (i=0; i<26; i++) *(p++) = 'A' + i; // Alphabet A1
|
||||
// Alphabet A2
|
||||
*(p++) = 0;
|
||||
if (storyVersion() != 1) *(p++) = '\n';
|
||||
for (i=0; i<10; i++) *(p++) = '0' + i;
|
||||
*(p++) = '.';
|
||||
*(p++) = ',';
|
||||
*(p++) = '!';
|
||||
*(p++) = '?';
|
||||
*(p++) = '_';
|
||||
*(p++) = '#';
|
||||
*(p++) = '\'';
|
||||
*(p++) = '"';
|
||||
*(p++) = '/';
|
||||
*(p++) = '\\';
|
||||
if (storyVersion() == 1) *(p++) = '<';
|
||||
*(p++) = '-';
|
||||
*(p++) = ':';
|
||||
*(p++) = '(';
|
||||
*(p++) = ')';
|
||||
}
|
||||
|
|
87
src/variable.c
Normal file
87
src/variable.c
Normal file
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
#include "variable.h"
|
||||
#include "state.h"
|
||||
#include "portme.h"
|
||||
#include "messages.h"
|
||||
#include "story.h"
|
||||
#include "memory.h"
|
||||
|
||||
|
||||
uint32_t variableAddressGlobal(uint16_t var) {
|
||||
return storyGlobalVariableTableAddress() + ((var - 0x10) * 2);
|
||||
}
|
||||
|
||||
|
||||
uint16_t variableLoad(uint16_t var) {
|
||||
// Is it on the stack?
|
||||
if (var < 16) return __state.stack[variableAddress(var, 0)];
|
||||
// Nope, global.
|
||||
return ZPEEKW(variableAddressGlobal(var));
|
||||
}
|
||||
|
||||
|
||||
void variableStore(uint16_t var, uint16_t value) {
|
||||
uint32_t addr;
|
||||
|
||||
if (var < 16) {
|
||||
// On stack.
|
||||
addr = variableAddress(var, 1);
|
||||
__state.stack[addr] = value;
|
||||
} else {
|
||||
// Global.
|
||||
addr = variableAddressGlobal(var);
|
||||
ZPOKEW(addr, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint8_t variableAddress(uint8_t var, bool writing) {
|
||||
uint16_t numLocals;
|
||||
|
||||
if (var == 0) { // top of stack
|
||||
if (writing) {
|
||||
if (__state.sp >= sizeof(__state.stack)) portDie(MSG_INT_STACK_OVERFLOW);
|
||||
#ifdef DEBUGGING
|
||||
printf("Push stack\n");
|
||||
#endif
|
||||
return __state.sp++;
|
||||
} else {
|
||||
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
|
||||
printf("Pop stack\n");
|
||||
#endif
|
||||
return --__state.sp;
|
||||
} // writing
|
||||
} // var
|
||||
|
||||
if ((var >= 0x1) && (var <= 0xf)) { // Local var.
|
||||
if (__state.stack[__state.bp - 1] <= (var - 1)) portDie(MSG_INT_REF_UNALLOCATED_LOCAL);
|
||||
return __state.bp + (var - 1);
|
||||
}
|
||||
|
||||
return storyGlobalVariableTableAddress() + ((var - 0x10) * 2);
|
||||
}
|
199
src/zscii.c
Normal file
199
src/zscii.c
Normal file
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
#include "zscii.h"
|
||||
#include "portme.h"
|
||||
#include "messages.h"
|
||||
#include "story.h"
|
||||
#include "state.h"
|
||||
#include "memory.h"
|
||||
|
||||
|
||||
uint32_t zsciiDecode(uint32_t zstr, bool abbr, char *buf, uint32_t *bufLenP) {
|
||||
uint32_t bufLen = *bufLenP;
|
||||
uint16_t code = 0;
|
||||
uint8_t alphabet = 0;
|
||||
uint8_t useAbbrTable = 0;
|
||||
uint8_t zsciiCollector = 0;
|
||||
uint16_t zsciiCode = 0;
|
||||
uint32_t decodedChars = 0;
|
||||
uint32_t pc = zstr;
|
||||
char printVal = 0;
|
||||
uint32_t index;
|
||||
uint32_t ptr;
|
||||
uint16_t abbrAddr;
|
||||
uint32_t abbrDecodedChars;
|
||||
int8_t i;
|
||||
uint8_t ch;
|
||||
int16_t newShift;
|
||||
|
||||
do {
|
||||
code = ZPEEKW(pc);
|
||||
pc += 2;
|
||||
|
||||
// Characters are 5 bits each, packed three to a 16-bit word.
|
||||
for (i=10; i>=0; i-=5) {
|
||||
|
||||
newShift = 0;
|
||||
printVal = 0;
|
||||
ch = ((code >> i) & 0x1f);
|
||||
|
||||
if (zsciiCollector) {
|
||||
if (zsciiCollector == 2) {
|
||||
zsciiCode |= ((uint16_t)ch) << 5;
|
||||
} else {
|
||||
zsciiCode |= ((uint16_t)ch);
|
||||
}
|
||||
|
||||
zsciiCollector--;
|
||||
|
||||
if (!zsciiCollector) {
|
||||
printVal = zsciiDecodeChar(zsciiCode);
|
||||
if (printVal) {
|
||||
decodedChars++;
|
||||
if (bufLen) {
|
||||
*(buf++) = printVal;
|
||||
bufLen--;
|
||||
}
|
||||
}
|
||||
alphabet = 0;
|
||||
useAbbrTable = 0;
|
||||
zsciiCode = 0;
|
||||
} // !zsciiCollector
|
||||
|
||||
continue;
|
||||
|
||||
} else if (useAbbrTable) { // zsciiCollector
|
||||
|
||||
if (abbr) portDie(MSG_INT_NO_ABBR);
|
||||
|
||||
index = ((32 * (((uint32_t)useAbbrTable) - 1)) + (uint32_t)ch);
|
||||
ptr = storyAbbreviationTableAddress() + (index * 2);
|
||||
abbrAddr = ZPEEKW(ptr);
|
||||
ptr += 2;
|
||||
|
||||
abbrDecodedChars = bufLen;
|
||||
zsciiDecode(abbrAddr * 2, 1, buf, &abbrDecodedChars);
|
||||
decodedChars += abbrDecodedChars;
|
||||
buf += (bufLen < abbrDecodedChars) ? bufLen : abbrDecodedChars;
|
||||
bufLen = (bufLen < abbrDecodedChars) ? 0 : (bufLen - abbrDecodedChars);
|
||||
|
||||
useAbbrTable = 0;
|
||||
alphabet = 0; //***FIXME*** Version 3+ has no shift-lock but V1 needs it.
|
||||
|
||||
continue;
|
||||
|
||||
} // useAbbrTable
|
||||
|
||||
switch (ch) {
|
||||
case 0:
|
||||
printVal = ' ';
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (storyVersion() == 1) {
|
||||
printVal = '\n';
|
||||
} else {
|
||||
useAbbrTable = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
case 3:
|
||||
if (storyVersion() <= 2) {
|
||||
portDie(MSG_INT_V12_SHIFT);
|
||||
} else {
|
||||
useAbbrTable = ch;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
case 5:
|
||||
if (storyVersion() <= 2) {
|
||||
portDie(MSG_INT_V12_SHIFT_LOCK);
|
||||
} else {
|
||||
newShift = 1;
|
||||
alphabet = ch - 3;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if ((ch == 6) && (alphabet == 2)) {
|
||||
zsciiCollector = 2;
|
||||
} else {
|
||||
printVal = __state.alphabetTable[(alphabet * 26) + (ch - 6)];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (printVal) {
|
||||
decodedChars++;
|
||||
if (bufLen) {
|
||||
*(buf++) = printVal;
|
||||
bufLen--;
|
||||
}
|
||||
}
|
||||
|
||||
if (alphabet && !newShift) alphabet = 0;
|
||||
|
||||
} // for
|
||||
|
||||
// There is no NULL terminator, you look for a word with the top bit set.
|
||||
} while ((code & (1 << 15)) == 0);
|
||||
|
||||
*bufLenP = decodedChars;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
portPrintChars(__memoryBuffer, decodedChars);
|
||||
|
||||
return ret;
|
||||
}
|
Loading…
Add table
Reference in a new issue