C C BBC Microcomputer emulation package. C BBCMOS_MAIN - Machine Operating System emulation routines. C C Copyright Peter Coghlan 1996 C C All communication from the 6502 emulator is carried out by calling the C BBC_Mos routine. This routine in turn either carries out the requested C operation or calls another routine (eg BBC_Time) to do it. C C On entry, the 6502 registers can be found in the Y6502_Registers C common block. PC indicates the address which generated the C call to BBC_Mos and so can be used to differentiate between C different operating system calls and functions. C Subroutine BBC_Mos IMPLICIT INTEGER (A-Z) Include 'Bbc_Files.Inc' CHARACTER BUFFER*127 Integer *1 Y6502_Read_Memory Record /BbcFcbDef/ Bbc_Mos_Fcb Common /Y6502_Registers/ Pc, A, X, Y, P, SP, Flags Volatile Flags External Rms$_Fnf C C System calls : 1 - OSBYTE 2 - OSWORD 3 - OSWRCH 4 - OSRDCH C 5 - OSFILE 6 - OSARGS 7 - OSBGET 8 - OSBPUT C 9 - OSGBPB 10 - OSFIND 11 - OSFSC 12 - Others C Goto (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12), Pc - 768 C C Perform selected OSBYTE calls C 1 IF (A.EQ.0) THEN IF (X.EQ.0) THEN CALL BRK(247,'OS 1.2|') ELSE X=1 ENDIF ELSE IF (A.EQ.124.OR.A.EQ.126) THEN CALL Y6502_Write_Memory(255,0) ELSE IF (A.EQ.125) THEN CALL Y6502_Write_Memory(255,128) Else If (A .Eq. 127) Then Call Bbc_Ceof(X) ELSE IF (A.EQ.129) THEN Status = BBC_Osbyte_129(X, Y, P) If (.Not. Status) Call Exit ELSE IF (A.EQ.130) THEN X=0 Y=0 ELSE IF (A.EQ.131) THEN X=0 Y=8 ELSE IF (A.EQ.132.OR.A.EQ.133) THEN X=0 Y=247 ELSE IF (A.EQ.135) THEN Status = BBC_Osbyte_135(X, Y) If (.Not. Status) Call Exit ELSE IF (A.EQ.218) THEN ELSE IF (A.EQ.11.OR.A.EQ.12.OR.A.EQ.15) THEN ELSE WRITE (6,1000) A 1000 FORMAT(' *Unsupported OSBYTE call ',Z2) RETURN ENDIF RETURN C C Read a line from the keyboard (OSWORD 0) Also do 1 and 2. C Note bug in BBC manuals - Y should NOT include CR. C 2 If (A .Gt. 2) Then Write (6, 2000) A 2000 Format(' *Unsupported OSWORD call ', Z2) Return Endif Goto (2100,2200,2300), A + 1 C Osword 0 - Read a line from the keyboard 2100 Continue Status = BBC_Osword_0(X, Y, P) If (.Not. Status) Call Exit RETURN C Osword 1 - Read system clock 2200 Continue Call BBC_Time(1, X, Y) Return C Osword 2 - Set system clock 2300 Continue Call BBC_Time(2, X, Y) Return c c OSWRCH - Write a character to the screen c 3 Continue Call BBC_Oswrch(A) Return c c OSRDCH - Read a character from the keyboard c 4 Continue Status = BBC_Osrdch(A, P) If (.Not. Status) Call Exit Return C C OSFILE - Operations on whole files C 5 Continue Call Bbc_Osfile(A, X, Y) Return C C OSARGS - Manipulate file arguments C 6 Continue Call Bbc_Osargs(A, X, Y) C C For some bizarre reason, OSARGS exits with the decimal flag cleared C while for other filing system routines, it is undefined. C P = P .And. .Not. 8 Return C C OSBGET - Read a byte from an open file C 7 Continue Call Bbc_Osbget(A, Y, P) Return C C OSBPUT - Write a byte to an open file C 8 Continue Call Bbc_Osbput(A, Y) Return C C OSGBPB - Read or write blocks of data C 9 Continue Call Bbc_OsGbPb(A, X, Y, P) Return C C OSFIND - Open files for random access C 10 Continue Call Bbc_Osfind(A, X, Y) Return C C OSFSC - Miscellaneous filing system routines C 11 Continue If (A .Eq. 1) Then Call Bbc_Ceof(X) Else IF (A.EQ.2.OR.A.EQ.4) THEN C *RUN RUNADR=X+Y*256 Call Bbc_GetString(Buffer, Runadr) Bbc_Mos_Fcb.Exec = 1 Rc = Bbc_Load_File(Bbc_Mos_Fcb, Buffer) IF (RC.EQ.%Loc(Rms$_Fnf)) CALL BRK(214,'File not found|') IF (.Not. RC) RETURN A=1 CALL EXECUT(Bbc_Mos_Fcb.Exec) ELSE IF (A.EQ.3) THEN CALL BRK(254,'Bad command|') ELSE IF (A.EQ.5) THEN C *CAT ADDR=X+Y*256 Buffer = ' ' DO 1104 I=1,80 TEMP=Y6502_Read_Memory(ADDR+I-1) IF (TEMP.EQ.13) GOTO 1105 BUFFER(I:I)=char(TEMP) 1104 CONTINUE 1105 CONTINUE Call BBC_Spawn('DIRECTORY ' // BUFFER(1:I)) ENDIF RETURN C C Perform miscellaneous tasks, mainly from OSCLI C 12 IF (A.EQ.0) THEN C CALL NXTCMD('DEFINE PFn =WHATEVER',?,228) ELSE IF (A.EQ.1) THEN C *SPAWN ADDR=X+Y*256 Buffer = ' ' DO 1201 I=1,80 TEMP=Y6502_Read_Memory(ADDR+I-1) IF (TEMP.EQ.13) GOTO 1202 BUFFER(I:I)=char(TEMP) 1201 CONTINUE 1202 CONTINUE CALL BBC_Spawn(BUFFER(1:I)) ENDIF RETURN END C C Error encountered in OS. Write a BRK plus message to the end of C the stack and execute it - paged rom style. C SUBROUTINE BRK(ERR,ERRSTR) IMPLICIT INTEGER (A-Z) CHARACTER ERRSTR*80 CALL Y6502_Write_Memory(256,0) CALL Y6502_Write_Memory(257,ERR) I=1 1 CALL Y6502_Write_Memory(257+I,ichar(ERRSTR(I:I))) I=I+1 IF (ERRSTR(I:I).NE.'|') GOTO 1 CALL Y6502_Write_Memory(257+I,0) CALL EXECUT(256) RETURN END C C Fix the return address on the stack to start execution elsewhere C SUBROUTINE EXECUT(ADDR) IMPLICIT INTEGER (A-Z) COMMON /Y6502_Registers/ PC,A,X,Y,P,SP, Flags Volatile Flags CALL Y6502_Write_Memory(SP+256,iAND(ADDR-1,65280)/256) SP=iAND(SP-1,255) CALL Y6502_Write_Memory(SP+256,ADDR-1) SP=iAND(SP-1,255) RETURN END