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
+280 -77

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 target_sources(${CMAKE_PROJECT_NAME} PRIVATE
"src/main.c" src/main.c
"src/ram.c" src/ram.c
src/cpu.c src/cpu.c
src/rom.c src/rom.c
src/io.c src/memory.c
src/memoryMap.c src/file.c
src/screen.c
) )
target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE 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 SCREEN_ADDRESS 0
#define KEYBOARD_ADDRESS 1 #define KEYBOARD_ADDRESS 1
#define ROM_BANKED_OUT 2 #define ROM_BANKED_OUT 2
#define FILE_COMMAND 3
int putChar(uint8_t c); #define FILE_DESCRIPTOR 4
int getChar(void); #define FILE_DATA 5 // two bytes, for pointer to string
#define FILE_STATUS 7
#endif // IO_H #endif // IO_H
+5 -3
View File
@@ -1,11 +1,13 @@
#ifndef MEMORY_MAP_H #ifndef MEMORY_H
#define MEMORY_MAP_H #define MEMORY_H
#include <stdint.h> #include <stdint.h>
#include "file.h"
#include "io.h" #include "io.h"
#include "ram.h" #include "ram.h"
#include "rom.h" #include "rom.h"
#include "screen.h"
uint8_t readMemory(uint16_t address, uint8_t *ram, uint8_t *rom); uint8_t readMemory(uint16_t address, uint8_t *ram, uint8_t *rom);
void writeMemory(uint16_t address, uint8_t value, uint8_t *ram); 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); uint8_t readStack(uint8_t address, uint8_t *ram);
void writeStack(uint8_t address, uint8_t value, 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 WIDTH2 := 70 ; mac column for zoned print
RAMSTART2 := $0400 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_FP := 5
BYTES_PER_ELEMENT := BYTES_FP BYTES_PER_ELEMENT := BYTES_FP
BYTES_PER_VARIABLE := BYTES_FP+2 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_ILLDIR, "ILLEGAL DIRECT"
define_error ERR_BADTYPE, "TYPE MISMATCH" define_error ERR_BADTYPE, "TYPE MISMATCH"
define_error ERR_STRLONG, "STRING TOO LONG" define_error ERR_STRLONG, "STRING TOO LONG"
.ifdef CONFIG_FILE
define_error ERR_BADDATA, "FILE DATA" define_error ERR_BADDATA, "FILE DATA"
.endif
define_error ERR_FRMCPX, "FORMULA TOO COMPLEX" define_error ERR_FRMCPX, "FORMULA TOO COMPLEX"
define_error ERR_CANTCONT, "CAN'T CONTINUE" define_error ERR_CANTCONT, "CAN'T CONTINUE"
define_error ERR_UNDEFFN, "UNDEF'D FUNCTION" define_error ERR_UNDEFFN, "UNDEF'D FUNCTION"
+106 -14
View File
@@ -1,34 +1,126 @@
.segment "EXTRA" .segment "EXTRA"
LOAD: ; IO
CHKIN:
stx CURDVC
stx IO_FILE_DESCRIPTOR
lda IO_COMMAND_SELECT_IN
sta IO_FILE_COMMAND
rts rts
SAVE: CHKOUT:
stx CURDVC
stx IO_FILE_DESCRIPTOR
lda IO_COMMAND_SELECT_OUT
sta IO_FILE_COMMAND
rts 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: ISCNTC:
lda $BC01 lda IO_KBD
cmp #$03 cmp #$03
beq :+ beq :+
rts rts
: :
jmp STOP jmp STOP
MONRDKEY: SYS:
lda $BC01 jsr GTNUM
bmi :+ lda LINNUM
sta $BC00 ; echo sta SYSJMP+1
: lda LINNUM+1
sta SYSJMP+2
SYSJMP:
jsr $FFFF
rts rts
MONCOUT: MONRDKEY := CHRIN
sta $BC00 MONCOUT := CHROUT
rts
.segment "WOZMON" .segment "WOZMON"
.include "wozmon.s" .include "wozmon.s"
.segment "RESETVEC" .segment "RESETVEC"
.word $0000 ; NMI vector .word $0000 ; NMI vector
.word COLD_START ; RESET vector .word COLD_START ; RESET vector
.word $0000 ; IRQ vector .word $0000 ; IRQ vector
+2 -2
View File
@@ -77,9 +77,9 @@ L4098:
sta INPUTBUFFER-4 sta INPUTBUFFER-4
ldx #TEMPST ldx #TEMPST
stx TEMPPT stx TEMPPT
lda #<$BC00 ; Start of IO lda #<IO_SCREEN ; Start of IO
sta MEMSIZ sta MEMSIZ
lda #>$BC00 lda #>IO_SCREEN
sta MEMSIZ+1 sta MEMSIZ+1
sta FRETOP sta FRETOP
sty FRETOP+1 sty FRETOP+1
-4
View File
@@ -40,13 +40,9 @@ L2453:
jmp L29B9 jmp L29B9
GETLN: GETLN:
.ifdef CONFIG_FILE
jsr CHRIN jsr CHRIN
ldy CURDVC ldy CURDVC
bne L2465 bne L2465
.else
jsr MONRDKEY
.endif
cmp #$0F cmp #$0F
bne L2465 bne L2465
pha pha
+2 -20
View File
@@ -22,13 +22,11 @@ L2A67:
SYNERR4: SYNERR4:
jmp SYNERR jmp SYNERR
RESPERR: RESPERR:
.ifdef CONFIG_FILE
lda CURDVC lda CURDVC
beq LCA8F beq LCA8F
ldx #ERR_BADDATA ldx #ERR_BADDATA
jmp ERROR jmp ERROR
LCA8F: LCA8F:
.endif
lda #<ERRREENTRY lda #<ERRREENTRY
ldy #>ERRREENTRY ldy #>ERRREENTRY
jsr STROUT jsr STROUT
@@ -45,7 +43,6 @@ RTS20:
GET: GET:
jsr ERRDIR jsr ERRDIR
; CBM: if GET#, then switch input ; CBM: if GET#, then switch input
.ifdef CONFIG_FILE
cmp #'#' cmp #'#'
bne LCAB6 bne LCAB6
jsr CHRGET jsr CHRGET
@@ -55,7 +52,6 @@ GET:
jsr CHKIN jsr CHKIN
stx CURDVC stx CURDVC
LCAB6: LCAB6:
.endif
ldx #<(INPUTBUFFER+1) ldx #<(INPUTBUFFER+1)
ldy #>(INPUTBUFFER+1) ldy #>(INPUTBUFFER+1)
lda #$00 lda #$00
@@ -63,16 +59,13 @@ LCAB6:
lda #$40 lda #$40
jsr PROCESS_INPUT_LIST jsr PROCESS_INPUT_LIST
; CBM: if GET#, then switch input back ; CBM: if GET#, then switch input back
.ifdef CONFIG_FILE
ldx CURDVC ldx CURDVC
bne LCAD8 bne LCAD8
.endif
rts rts
; ---------------------------------------------------------------------------- ; ----------------------------------------------------------------------------
; "INPUT#" STATEMENT ; "INPUT#" STATEMENT
; ---------------------------------------------------------------------------- ; ----------------------------------------------------------------------------
.ifdef CONFIG_FILE
INPUTH: INPUTH:
jsr GETBYT jsr GETBYT
lda #$2C lda #$2C
@@ -88,7 +81,6 @@ LCAD8:
stx CURDVC stx CURDVC
rts rts
LCAE0: LCAE0:
.endif
; ---------------------------------------------------------------------------- ; ----------------------------------------------------------------------------
; "INPUT" STATEMENT ; "INPUT" STATEMENT
@@ -107,30 +99,24 @@ L2A9E:
sta INPUTBUFFER-1 sta INPUTBUFFER-1
LCAF8: LCAF8:
jsr NXIN jsr NXIN
.ifdef CONFIG_FILE
lda CURDVC lda CURDVC
beq LCB0C beq LCB0C
lda Z96 lda IO_FILE_STATUS
and #$02 and #FILE_STATUS_EOF
beq LCB0C beq LCB0C
jsr LCAD6 jsr LCAD6
jmp DATA jmp DATA
LCB0C: LCB0C:
.endif
lda INPUTBUFFER lda INPUTBUFFER
bne L2ABE bne L2ABE
.ifdef CONFIG_FILE
lda CURDVC lda CURDVC
bne LCAF8 bne LCAF8
.endif
clc clc
jmp CONTROL_C_TYPED jmp CONTROL_C_TYPED
NXIN: NXIN:
.ifdef CONFIG_FILE
lda CURDVC lda CURDVC
bne LCB21 bne LCB21
.endif
jsr OUTQUES ; '?' jsr OUTQUES ; '?'
jsr OUTSP jsr OUTSP
LCB21: LCB21:
@@ -196,10 +182,8 @@ PROCESS_INPUT_ITEM:
bne L2AF8 ; always bne L2AF8 ; always
L2AF0: L2AF0:
bmi FINDATA bmi FINDATA
.ifdef CONFIG_FILE
lda CURDVC lda CURDVC
bne LCB64 bne LCB64
.endif
jsr OUTQUES jsr OUTQUES
LCB64: LCB64:
jsr NXIN jsr NXIN
@@ -300,10 +284,8 @@ L2B94:
ldy #$00 ldy #$00
lda (INPTR),y lda (INPTR),y
beq L2BA1 beq L2BA1
.ifdef CONFIG_FILE
lda CURDVC lda CURDVC
bne L2BA1 bne L2BA1
.endif
lda #<ERREXTRA lda #<ERREXTRA
ldy #>ERREXTRA ldy #>ERREXTRA
jmp STROUT jmp STROUT
-3
View File
@@ -142,7 +142,6 @@ L2963:
RET5: RET5:
rts rts
.ifdef CONFIG_FILE
PRINTH: PRINTH:
jsr CMD jsr CMD
jmp LCAD6 jmp LCAD6
@@ -157,5 +156,3 @@ LC98F:
stx CURDVC stx CURDVC
plp plp
jmp PRINT jmp PRINT
.endif
-6
View File
@@ -43,10 +43,8 @@ L29B9:
sta INPUTBUFFER,x sta INPUTBUFFER,x
ldx #<(INPUTBUFFER-1) ldx #<(INPUTBUFFER-1)
ldy #>(INPUTBUFFER-1) ldy #>(INPUTBUFFER-1)
.ifdef CONFIG_FILE
lda CURDVC lda CURDVC
bne L29DD bne L29DD
.endif
CRDO: CRDO:
lda #CR lda #CR
@@ -124,7 +122,6 @@ L2A22:
jmp L2A22 jmp L2A22
; ---------------------------------------------------------------------------- ; ----------------------------------------------------------------------------
OUTSP: OUTSP:
.ifdef CONFIG_FILE
; on non-screen devices, print SPACE ; on non-screen devices, print SPACE
; instead of CRSR RIGHT ; instead of CRSR RIGHT
lda CURDVC lda CURDVC
@@ -133,9 +130,6 @@ OUTSP:
.byte $2C .byte $2C
LCA40: LCA40:
lda #$1D ; CRSR RIGHT lda #$1D ; CRSR RIGHT
.else
lda #$20
.endif
.byte $2C .byte $2C
OUTQUES: OUTQUES:
lda #$3F lda #$3F
-2
View File
@@ -20,14 +20,12 @@ MEMERR:
; ---------------------------------------------------------------------------- ; ----------------------------------------------------------------------------
ERROR: ERROR:
lsr Z14 lsr Z14
.ifdef CONFIG_FILE
lda CURDVC ; output lda CURDVC ; output
beq LC366 ; is screen beq LC366 ; is screen
jsr CLRCH ; otherwise redirect output back to screen jsr CLRCH ; otherwise redirect output back to screen
lda #$00 lda #$00
sta CURDVC sta CURDVC
LC366: LC366:
.endif
jsr CRDO jsr CRDO
jsr OUTQUES jsr OUTQUES
L2329: L2329:
-6
View File
@@ -6,9 +6,7 @@
keyword_rts "FOR", FOR keyword_rts "FOR", FOR
keyword_rts "NEXT", NEXT keyword_rts "NEXT", NEXT
keyword_rts "DATA", DATA keyword_rts "DATA", DATA
.ifdef CONFIG_FILE
keyword_rts "INPUT#", INPUTH keyword_rts "INPUT#", INPUTH
.endif
keyword_rts "INPUT", INPUT keyword_rts "INPUT", INPUT
keyword_rts "DIM", DIM keyword_rts "DIM", DIM
keyword_rts "READ", READ keyword_rts "READ", READ
@@ -25,19 +23,15 @@
keyword_rts "WAIT", WAIT keyword_rts "WAIT", WAIT
keyword_rts "DEF", DEF keyword_rts "DEF", DEF
keyword_rts "POKE", POKE keyword_rts "POKE", POKE
.ifdef CONFIG_FILE
keyword_rts "PRINT#", PRINTH keyword_rts "PRINT#", PRINTH
.endif
keyword_rts "PRINT", PRINT, TOKEN_PRINT keyword_rts "PRINT", PRINT, TOKEN_PRINT
keyword_rts "CONT", CONT keyword_rts "CONT", CONT
keyword_rts "LIST", LIST keyword_rts "LIST", LIST
keyword_rts "CLEAR", CLEAR keyword_rts "CLEAR", CLEAR
.ifdef CONFIG_FILE
keyword_rts "CMD", CMD keyword_rts "CMD", CMD
keyword_rts "SYS", SYS keyword_rts "SYS", SYS
keyword_rts "OPEN", OPEN keyword_rts "OPEN", OPEN
keyword_rts "CLOSE", CLOSE keyword_rts "CLOSE", CLOSE
.endif
keyword_rts "GET", GET keyword_rts "GET", GET
keyword_rts "NEW", NEW 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. BMI GETLINE ; Beyond start of line, reinitialize.
NEXTCHAR: NEXTCHAR:
LDA $BC01 ; Check status. LDA IO_KBD ; Check status.
BMI NEXTCHAR ; Loop until ready. BMI NEXTCHAR ; Loop until ready.
STA IN,Y ; Add to text buffer. STA IN,Y ; Add to text buffer.
JSR ECHO ; Display character. JSR ECHO ; Display character.
@@ -165,5 +165,5 @@ PRHEX:
ADC #$06 ; Add offset for letter. ADC #$06 ; Add offset for letter.
ECHO: ECHO:
STA $BC00 ; Output character. STA IO_SCREEN ; Output character.
RTS ; Return. RTS ; Return.
+3 -2
View File
@@ -28,7 +28,6 @@ TXPSV:
INPUTBUFFER = $0200 INPUTBUFFER = $0200
.org $12 .org $12
CHARAC: CHARAC:
.res 1 .res 1
ENDCHR: ENDCHR:
@@ -51,7 +50,6 @@ Z14:
.res 1 .res 1
.org $1D .org $1D
TEMPPT: TEMPPT:
.res 1 .res 1
LASTPT: LASTPT:
@@ -156,3 +154,6 @@ TXTPTR = <(GENERIC_TXTPTR-GENERIC_CHRGET + CHRGET)
CHRGOT = <(GENERIC_CHRGOT-GENERIC_CHRGET + CHRGET) CHRGOT = <(GENERIC_CHRGOT-GENERIC_CHRGET + CHRGET)
CHRGOT2 = <(GENERIC_CHRGOT2-GENERIC_CHRGET + CHRGET) CHRGOT2 = <(GENERIC_CHRGOT2-GENERIC_CHRGET + CHRGET)
RNDSEED = <(GENERIC_RNDSEED-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 "cpu.h"
#include "memoryMap.h" #include "memory.h"
#include "opcodes.h" #include "opcodes.h"
#define COMBINE(H, L) ((H << 8) | L) #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("6502PC Emulator with MS Basic\n");
printf("CTRL + G to exit\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); 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) { uint8_t readMemory(uint16_t address, uint8_t *ram, uint8_t *rom) {
// RAM/ROM // RAM/ROM
@@ -16,10 +16,18 @@ uint8_t readMemory(uint16_t address, uint8_t *ram, uint8_t *rom) {
case KEYBOARD_ADDRESS: { case KEYBOARD_ADDRESS: {
return getChar(); return getChar();
} }
case ROM_BANKED_OUT: { case ROM_BANKED_OUT: {
return ram[IO_BASE + 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: default:
break; break;
} }
@@ -55,6 +63,33 @@ void writeMemory(uint16_t address, uint8_t value, uint8_t *ram) {
ram[IO_BASE + ROM_BANKED_OUT] = value; ram[IO_BASE + ROM_BANKED_OUT] = value;
break; 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: default:
break; break;
} }
+1 -1
View File
@@ -1,4 +1,4 @@
#include "io.h" #include "screen.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>