Start on FILE i/O

This commit is contained in:
Kilian committed 2026-09-28 14:44:11 +02:00
1 parent 7033104799
commit 03518c4937
22 files changed
+277 -74

No files matched your search

+5 -4
View File
@@ -23,12 +23,13 @@ target_compile_options(${CMAKE_PROJECT_NAME} PRIVATE
)
target_sources(${CMAKE_PROJECT_NAME} PRIVATE
"src/main.c"
"src/ram.c"
src/main.c
src/ram.c
src/cpu.c
src/rom.c
src/io.c
src/memoryMap.c
src/memory.c
src/file.c
src/screen.c
)
target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE
+17
View File
@@ -0,0 +1,17 @@
#ifndef FILE_H
#define FILE_H
#define COMMAND_OPEN 1
#define COMMAND_CLOSE 2
#define COMMAND_SELECT_IN 3
#define COMMAND_SELECT_OUT 4
#define COMMAND_READ 5
#define COMMAND_WRITE 6
#define COMMAND_RESET 7
int openFile(int fd, const char *path);
int closeFile(int fd);
int readByte(const int fd, int *data);
int writeByte(const int fd, const int data);
#endif // FILE_H
+4 -3
View File
@@ -9,8 +9,9 @@
#define SCREEN_ADDRESS 0
#define KEYBOARD_ADDRESS 1
#define ROM_BANKED_OUT 2
int putChar(uint8_t c);
int getChar(void);
#define FILE_COMMAND 3
#define FILE_DESCRIPTOR 4
#define FILE_DATA 5 // two bytes, for pointer to string
#define FILE_STATUS 7
#endif // IO_H
+5 -3
View File
@@ -1,11 +1,13 @@
#ifndef MEMORY_MAP_H
#define MEMORY_MAP_H
#ifndef MEMORY_H
#define MEMORY_H
#include <stdint.h>
#include "file.h"
#include "io.h"
#include "ram.h"
#include "rom.h"
#include "screen.h"
uint8_t readMemory(uint16_t address, uint8_t *ram, uint8_t *rom);
void writeMemory(uint16_t address, uint8_t value, uint8_t *ram);
@@ -13,4 +15,4 @@ void writeMemory(uint16_t address, uint8_t value, uint8_t *ram);
uint8_t readStack(uint8_t address, uint8_t *ram);
void writeStack(uint8_t address, uint8_t value, uint8_t *ram);
#endif // MEMORY_MAP_H
#endif // MEMORY_H
+9
View File
@@ -0,0 +1,9 @@
#ifndef SCREEN_H
#define SCREEN_H
#include <stdint.h>
int putChar(uint8_t c);
int getChar(void);
#endif // SCREEN_H
+23
View File
@@ -5,6 +5,29 @@ WIDTH := 80 ; Default terminal width
WIDTH2 := 70 ; mac column for zoned print
RAMSTART2 := $0400
; io registers
IO_SCREEN := $BC00
IO_KBD := $BC01
IO_ROM_BANKED_OUT := $BC02
IO_FILE_COMMAND := $BC03
IO_FILE_DESCRIPTOR := $BC04
IO_FILE_DATA := $BC05
IO_FILE_STATUS := $BC07
; io commands
IO_COMMAND_OPEN := 1
IO_COMMAND_CLOSE := 2
IO_COMMAND_SELECT_IN := 3
IO_COMMAND_SELECT_OUT := 4
IO_COMMAND_READ := 5
IO_COMMAND_WRITE := 6
IO_COMMAND_RESET := 7
; io status
FILE_STATUS_ERROR := $01
FILE_STATUS_EOF := $02
FILE_STATUS_READY := $04
BYTES_FP := 5
BYTES_PER_ELEMENT := BYTES_FP
BYTES_PER_VARIABLE := BYTES_FP+2
-2
View File
@@ -14,9 +14,7 @@ define_error ERR_ZERODIV, "DIVISION BY ZERO"
define_error ERR_ILLDIR, "ILLEGAL DIRECT"
define_error ERR_BADTYPE, "TYPE MISMATCH"
define_error ERR_STRLONG, "STRING TOO LONG"
.ifdef CONFIG_FILE
define_error ERR_BADDATA, "FILE DATA"
.endif
define_error ERR_FRMCPX, "FORMULA TOO COMPLEX"
define_error ERR_CANTCONT, "CAN'T CONTINUE"
define_error ERR_UNDEFFN, "UNDEF'D FUNCTION"
+103 -11
View File
@@ -1,29 +1,121 @@
.segment "EXTRA"
LOAD:
; IO
CHKIN:
stx CURDVC
stx IO_FILE_DESCRIPTOR
lda IO_COMMAND_SELECT_IN
sta IO_FILE_COMMAND
rts
SAVE:
CHKOUT:
stx CURDVC
stx IO_FILE_DESCRIPTOR
lda IO_COMMAND_SELECT_OUT
sta IO_FILE_COMMAND
rts
CLRCH:
lda #0
sta CURDVC
lda IO_COMMAND_RESET
sta IO_FILE_COMMAND
rts
CHRIN:
lda CURDVC
bne @file
lda IO_KBD
bmi @end
jsr CHROUT ; echo
@file:
lda IO_COMMAND_READ
sta IO_FILE_COMMAND
@wait:
lda IO_FILE_STATUS
and #FILE_STATUS_READY
beq @wait
lda IO_FILE_DATA
@end:
rts
CHROUT:
lda CURDVC
bne @file
sta IO_SCREEN
rts
@file:
sta IO_FILE_DATA
lda IO_COMMAND_WRITE
sta IO_FILE_COMMAND
@wait:
lda IO_FILE_STATUS
and #$4
beq @wait
rts
OPEN:
jsr GETBYT
stx IO_FILE_DESCRIPTOR
jsr CHKCOM
jsr FRMEVL
jsr CHKSTR
jsr FREFAC
sta STRNG2
ldy #0
@copy:
cpy STRNG2
beq @done_copy
lda (INDEX),y
sta FILE_NAME_BUFFER,y
iny
bne @copy
@done_copy:
lda #0
sta FILE_NAME_BUFFER,y
lda #<FILE_NAME_BUFFER
sta IO_FILE_DATA
lda #>FILE_NAME_BUFFER
sta IO_FILE_DATA+1
lda #IO_COMMAND_OPEN
sta IO_FILE_COMMAND
@wait:
lda IO_FILE_STATUS
and #FILE_STATUS_READY
beq @wait
lda #FILE_STATUS_READY
and #$01
bne @error
rts
@error:
jmp IQERR
CLOSE:
rts
; Default
ISCNTC:
lda $BC01
lda IO_KBD
cmp #$03
beq :+
rts
:
jmp STOP
MONRDKEY:
lda $BC01
bmi :+
sta $BC00 ; echo
:
SYS:
jsr GTNUM
lda LINNUM
sta SYSJMP+1
lda LINNUM+1
sta SYSJMP+2
SYSJMP:
jsr $FFFF
rts
MONCOUT:
sta $BC00
rts
MONRDKEY := CHRIN
MONCOUT := CHROUT
.segment "WOZMON"
.include "wozmon.s"
+2 -2
View File
@@ -77,9 +77,9 @@ L4098:
sta INPUTBUFFER-4
ldx #TEMPST
stx TEMPPT
lda #<$BC00 ; Start of IO
lda #<IO_SCREEN ; Start of IO
sta MEMSIZ
lda #>$BC00
lda #>IO_SCREEN
sta MEMSIZ+1
sta FRETOP
sty FRETOP+1
-4
View File
@@ -40,13 +40,9 @@ L2453:
jmp L29B9
GETLN:
.ifdef CONFIG_FILE
jsr CHRIN
ldy CURDVC
bne L2465
.else
jsr MONRDKEY
.endif
cmp #$0F
bne L2465
pha
+2 -20
View File
@@ -22,13 +22,11 @@ L2A67:
SYNERR4:
jmp SYNERR
RESPERR:
.ifdef CONFIG_FILE
lda CURDVC
beq LCA8F
ldx #ERR_BADDATA
jmp ERROR
LCA8F:
.endif
lda #<ERRREENTRY
ldy #>ERRREENTRY
jsr STROUT
@@ -45,7 +43,6 @@ RTS20:
GET:
jsr ERRDIR
; CBM: if GET#, then switch input
.ifdef CONFIG_FILE
cmp #'#'
bne LCAB6
jsr CHRGET
@@ -55,7 +52,6 @@ GET:
jsr CHKIN
stx CURDVC
LCAB6:
.endif
ldx #<(INPUTBUFFER+1)
ldy #>(INPUTBUFFER+1)
lda #$00
@@ -63,16 +59,13 @@ LCAB6:
lda #$40
jsr PROCESS_INPUT_LIST
; CBM: if GET#, then switch input back
.ifdef CONFIG_FILE
ldx CURDVC
bne LCAD8
.endif
rts
; ----------------------------------------------------------------------------
; "INPUT#" STATEMENT
; ----------------------------------------------------------------------------
.ifdef CONFIG_FILE
INPUTH:
jsr GETBYT
lda #$2C
@@ -88,7 +81,6 @@ LCAD8:
stx CURDVC
rts
LCAE0:
.endif
; ----------------------------------------------------------------------------
; "INPUT" STATEMENT
@@ -107,30 +99,24 @@ L2A9E:
sta INPUTBUFFER-1
LCAF8:
jsr NXIN
.ifdef CONFIG_FILE
lda CURDVC
beq LCB0C
lda Z96
and #$02
lda IO_FILE_STATUS
and #FILE_STATUS_EOF
beq LCB0C
jsr LCAD6
jmp DATA
LCB0C:
.endif
lda INPUTBUFFER
bne L2ABE
.ifdef CONFIG_FILE
lda CURDVC
bne LCAF8
.endif
clc
jmp CONTROL_C_TYPED
NXIN:
.ifdef CONFIG_FILE
lda CURDVC
bne LCB21
.endif
jsr OUTQUES ; '?'
jsr OUTSP
LCB21:
@@ -196,10 +182,8 @@ PROCESS_INPUT_ITEM:
bne L2AF8 ; always
L2AF0:
bmi FINDATA
.ifdef CONFIG_FILE
lda CURDVC
bne LCB64
.endif
jsr OUTQUES
LCB64:
jsr NXIN
@@ -300,10 +284,8 @@ L2B94:
ldy #$00
lda (INPTR),y
beq L2BA1
.ifdef CONFIG_FILE
lda CURDVC
bne L2BA1
.endif
lda #<ERREXTRA
ldy #>ERREXTRA
jmp STROUT
-3
View File
@@ -142,7 +142,6 @@ L2963:
RET5:
rts
.ifdef CONFIG_FILE
PRINTH:
jsr CMD
jmp LCAD6
@@ -157,5 +156,3 @@ LC98F:
stx CURDVC
plp
jmp PRINT
.endif
-6
View File
@@ -43,10 +43,8 @@ L29B9:
sta INPUTBUFFER,x
ldx #<(INPUTBUFFER-1)
ldy #>(INPUTBUFFER-1)
.ifdef CONFIG_FILE
lda CURDVC
bne L29DD
.endif
CRDO:
lda #CR
@@ -124,7 +122,6 @@ L2A22:
jmp L2A22
; ----------------------------------------------------------------------------
OUTSP:
.ifdef CONFIG_FILE
; on non-screen devices, print SPACE
; instead of CRSR RIGHT
lda CURDVC
@@ -133,9 +130,6 @@ OUTSP:
.byte $2C
LCA40:
lda #$1D ; CRSR RIGHT
.else
lda #$20
.endif
.byte $2C
OUTQUES:
lda #$3F
-2
View File
@@ -20,14 +20,12 @@ MEMERR:
; ----------------------------------------------------------------------------
ERROR:
lsr Z14
.ifdef CONFIG_FILE
lda CURDVC ; output
beq LC366 ; is screen
jsr CLRCH ; otherwise redirect output back to screen
lda #$00
sta CURDVC
LC366:
.endif
jsr CRDO
jsr OUTQUES
L2329:
-6
View File
@@ -6,9 +6,7 @@
keyword_rts "FOR", FOR
keyword_rts "NEXT", NEXT
keyword_rts "DATA", DATA
.ifdef CONFIG_FILE
keyword_rts "INPUT#", INPUTH
.endif
keyword_rts "INPUT", INPUT
keyword_rts "DIM", DIM
keyword_rts "READ", READ
@@ -25,19 +23,15 @@
keyword_rts "WAIT", WAIT
keyword_rts "DEF", DEF
keyword_rts "POKE", POKE
.ifdef CONFIG_FILE
keyword_rts "PRINT#", PRINTH
.endif
keyword_rts "PRINT", PRINT, TOKEN_PRINT
keyword_rts "CONT", CONT
keyword_rts "LIST", LIST
keyword_rts "CLEAR", CLEAR
.ifdef CONFIG_FILE
keyword_rts "CMD", CMD
keyword_rts "SYS", SYS
keyword_rts "OPEN", OPEN
keyword_rts "CLOSE", CLOSE
.endif
keyword_rts "GET", GET
keyword_rts "NEW", NEW
+2 -2
View File
@@ -33,7 +33,7 @@ BACKSPACE: DEY ; Back up text index.
BMI GETLINE ; Beyond start of line, reinitialize.
NEXTCHAR:
LDA $BC01 ; Check status.
LDA IO_KBD ; Check status.
BMI NEXTCHAR ; Loop until ready.
STA IN,Y ; Add to text buffer.
JSR ECHO ; Display character.
@@ -165,5 +165,5 @@ PRHEX:
ADC #$06 ; Add offset for letter.
ECHO:
STA $BC00 ; Output character.
STA IO_SCREEN ; Output character.
RTS ; Return.
+3 -2
View File
@@ -28,7 +28,6 @@ TXPSV:
INPUTBUFFER = $0200
.org $12
CHARAC:
.res 1
ENDCHR:
@@ -51,7 +50,6 @@ Z14:
.res 1
.org $1D
TEMPPT:
.res 1
LASTPT:
@@ -156,3 +154,6 @@ TXTPTR = <(GENERIC_TXTPTR-GENERIC_CHRGET + CHRGET)
CHRGOT = <(GENERIC_CHRGOT-GENERIC_CHRGET + CHRGET)
CHRGOT2 = <(GENERIC_CHRGOT2-GENERIC_CHRGET + CHRGET)
RNDSEED = <(GENERIC_RNDSEED-GENERIC_CHRGET + CHRGET)
CURDVC:
.res 1
FILE_NAME_BUFFER = $0300
+1 -1
View File
@@ -1,6 +1,6 @@
#include "cpu.h"
#include "memoryMap.h"
#include "memory.h"
#include "opcodes.h"
#define COMBINE(H, L) ((H << 8) | L)
+63
View File
@@ -0,0 +1,63 @@
#include "file.h"
#include <errno.h>
#include <stdio.h>
// Up to 256 files can be open
FILE *files[256];
int openFile(int fd, const char *path) {
files[fd] = fopen(path, "r+");
if (files[fd] == NULL) {
return errno;
}
return 0;
}
int closeFile(int fd) {
int ret = fclose(files[fd]);
if (ret != 0) {
return errno;
}
return 0;
}
int readByte(const int fd, int *data) {
int status = 0;
int count = fread(&data, 1, 1, files[fd]);
// Error or EOF
if (count != 1) {
int error = ferror(files[fd]);
int eof = feof(files[fd]);
if (error != 0) {
status = 0x2;
} else if (eof != 0) {
status = 0x1;
} else {
status = 0x4;
}
}
return status;
}
int writeByte(const int fd, const int data) {
int status = 0;
int count = fwrite(&data, 1, 1, files[fd]);
// Error or EOF
if (count != 1) {
int error = ferror(files[fd]);
int eof = feof(files[fd]);
if (error != 0) {
status = 0x2;
} else if (eof != 0) {
status = 0x1;
} else {
status = 0x4;
}
}
return status;
}
+1 -1
View File
@@ -46,7 +46,7 @@ int main(void) {
printf("6502PC Emulator with MS Basic\n");
printf("CTRL + G to exit\n");
printf("WOZMON available, BASIC at DF6A\n");
printf("WOZMON available, BASIC at E032\n");
clock_gettime(CLOCK_MONOTONIC, &emulationStart);
+36 -1
View File
@@ -1,4 +1,4 @@
#include "memoryMap.h"
#include "memory.h"
uint8_t readMemory(uint16_t address, uint8_t *ram, uint8_t *rom) {
// RAM/ROM
@@ -16,10 +16,18 @@ uint8_t readMemory(uint16_t address, uint8_t *ram, uint8_t *rom) {
case KEYBOARD_ADDRESS: {
return getChar();
}
case ROM_BANKED_OUT: {
return ram[IO_BASE + ROM_BANKED_OUT];
}
case FILE_DATA: {
return ram[IO_BASE + FILE_DATA];
}
case FILE_STATUS: {
return ram[IO_BASE + FILE_STATUS];
}
default:
break;
}
@@ -55,6 +63,33 @@ void writeMemory(uint16_t address, uint8_t value, uint8_t *ram) {
ram[IO_BASE + ROM_BANKED_OUT] = value;
break;
case FILE_COMMAND: {
switch (ram[IO_BASE + FILE_COMMAND]) {
case COMMAND_OPEN: {
ram[IO_BASE + FILE_STATUS] = 0;
ram[IO_BASE + FILE_STATUS] = openFile(ram[IO_BASE + FILE_DESCRIPTOR], (const char *)&ram[IO_BASE + FILE_DATA]);
break;
}
case COMMAND_CLOSE: {
ram[IO_BASE + FILE_STATUS] = 0;
ram[IO_BASE + FILE_STATUS] = closeFile(ram[IO_BASE + FILE_DESCRIPTOR]);
break;
}
default:
break;
}
break;
}
case FILE_DESCRIPTOR: {
ram[IO_BASE + FILE_DESCRIPTOR] = value;
break;
}
case FILE_DATA: {
ram[IO_BASE + FILE_DATA] = value;
break;
}
default:
break;
}
+1 -1
View File
@@ -1,4 +1,4 @@
#include "io.h"
#include "screen.h"
#include <stdio.h>
#include <stdlib.h>