mirror of
https://github.com/dschmenk/PLASMA.git
synced 2025-03-31 14:30:36 +00:00
1338 lines
24 KiB
Plaintext
1338 lines
24 KiB
Plaintext
const MACHID = $BF98
|
|
const iobuffer = $0800
|
|
const databuff = $2000
|
|
const MODADDR = $1000
|
|
const symtbl = $0C00
|
|
const freemem = $0006
|
|
const getlnbuf = $01FF
|
|
//
|
|
// System flags: memory allocator screen holes.
|
|
//
|
|
const restxt1 = $0001
|
|
const restxt2 = $0002
|
|
const resxtxt1 = $0004
|
|
const resxtxt2 = $0008
|
|
const reshgr1 = $0010
|
|
const reshgr2 = $0020
|
|
const resxhgr1 = $0040
|
|
const resxhgr2 = $0080
|
|
//
|
|
// Module don't free memory
|
|
//
|
|
const modkeep = $2000
|
|
const modinitkeep = $4000
|
|
//
|
|
// Pedefined functions.
|
|
//
|
|
predef syscall, call
|
|
predef crout, cout, prstr, cin, rdstr
|
|
predef markheap, allocheap, allocalignheap, releaseheap, availheap
|
|
predef memset, memcpy
|
|
predef uword_isgt, uword_isge, uword_islt, uword_isle
|
|
predef loadmod, execmod, lookupstrmod
|
|
//
|
|
// System variable.
|
|
//
|
|
word version = $0092 // 00.92
|
|
word systemflags = 0
|
|
word heap
|
|
word xheap = $0800
|
|
word lastsym = symtbl
|
|
byte perr
|
|
byte cmdln = "" // Overlay exported strings table
|
|
//
|
|
// Standard Library exported functions.
|
|
//
|
|
byte syslibstr = "CMDSYS"
|
|
byte machidstr = "MACHID"
|
|
byte sysstr = "SYSCALL"
|
|
byte callstr = "CALL"
|
|
byte putcstr = "PUTC"
|
|
byte putlnstr = "PUTLN"
|
|
byte putsstr = "PUTS"
|
|
byte getcstr = "GETC"
|
|
byte getsstr = "GETS"
|
|
byte hpmarkstr = "HEAPMARK"
|
|
byte hpalignstr = "HEAPALLOCALIGN"
|
|
byte hpallocstr = "HEAPALLOC"
|
|
byte hprelstr = "HEAPRELEASE"
|
|
byte memsetstr = "MEMSET"
|
|
byte memcpystr = "MEMCPY"
|
|
byte uisgtstr = "ISUGT"
|
|
byte uisgestr = "ISUGE"
|
|
byte uisltstr = "ISULT"
|
|
byte uislestr = "ISULE"
|
|
byte loadstr = "MODLOAD"
|
|
byte execstr = "MODEXEC"
|
|
byte modadrstr = "MODADDR"
|
|
byte argstr = "ARGS"
|
|
byte autorun = "AUTORUN"
|
|
byte prefix[] // overlay with exported symbols table
|
|
word exports = @sysstr, @syscall
|
|
word = @callstr, @call
|
|
word = @putcstr, @cout
|
|
word = @putlnstr, @crout
|
|
word = @putsstr, @prstr
|
|
word = @getcstr, @cin
|
|
word = @getsstr, @rdstr
|
|
word = @hpmarkstr, @markheap
|
|
word = @hpallocstr,@allocheap
|
|
word = @hpalignstr,@allocalignheap
|
|
word = @hprelstr, @releaseheap
|
|
word = @memsetstr, @memset
|
|
word = @memcpystr, @memcpy
|
|
word = @uisgtstr, @uword_isgt
|
|
word = @uisgestr, @uword_isge
|
|
word = @uisltstr, @uword_islt
|
|
word = @uislestr, @uword_isle
|
|
word = @loadstr, @loadmod
|
|
word = @execstr, @execmod
|
|
word = @modadrstr, @lookupstrmod
|
|
word = @machidstr, MACHID
|
|
word = @argstr, @cmdln
|
|
word = 0
|
|
word syslibsym = @exports
|
|
//
|
|
// Utility functions
|
|
//
|
|
//asm equates included from cmdstub.s
|
|
//
|
|
// CALL PRODOS
|
|
// SYSCALL(CMD, PARAMS)
|
|
//
|
|
asm syscall
|
|
LDA ESTKL,X
|
|
LDY ESTKH,X
|
|
STA PARAMS
|
|
STY PARAMS+1
|
|
INX
|
|
LDA ESTKL,X
|
|
STA CMD
|
|
JSR $BF00
|
|
CMD: !BYTE 00
|
|
PARAMS: !WORD 0000
|
|
LDY #$00
|
|
STA ESTKL,X
|
|
STY ESTKH,X
|
|
RTS
|
|
end
|
|
//
|
|
// CALL 6502 ROUTINE
|
|
// CALL(ADDR, AREG, XREG, YREG, STATUS)
|
|
//
|
|
asm call
|
|
REGVALS = SRC
|
|
PHP
|
|
LDA ESTKL+4,X
|
|
STA TMPL
|
|
LDA ESTKH+4,X
|
|
STA TMPH
|
|
LDA ESTKL,X
|
|
PHA
|
|
LDA ESTKL+1,X
|
|
TAY
|
|
LDA ESTKL+3,X
|
|
PHA
|
|
LDA ESTKL+2,X
|
|
INX
|
|
INX
|
|
INX
|
|
INX
|
|
STX ESP
|
|
TAX
|
|
PLA
|
|
BIT ROMEN
|
|
PLP
|
|
JSR JMPTMP
|
|
PHP
|
|
BIT LCRDEN+LCBNK2
|
|
STA REGVALS+0
|
|
STX REGVALS+1
|
|
STY REGVALS+2
|
|
PLA
|
|
STA REGVALS+3
|
|
LDX ESP
|
|
LDA #<REGVALS
|
|
LDY #>REGVALS
|
|
STA ESTKL,X
|
|
STY ESTKH,X
|
|
PLP
|
|
RTS
|
|
JMPTMP JMP (TMP)
|
|
end
|
|
//
|
|
// CALL LOADED SYSTEM PROGRAM
|
|
//
|
|
asm exec
|
|
LDX #$00
|
|
STX IFPL
|
|
LDA #$BF
|
|
STA IFPH
|
|
LDX #$FE
|
|
TXS
|
|
LDX #ESTKSZ/2
|
|
BIT ROMEN
|
|
JMP $2000
|
|
end
|
|
//
|
|
// EXIT
|
|
//
|
|
asm reboot
|
|
BIT ROMEN
|
|
DEC $03F4 ; INVALIDATE POWER-UP BYTE
|
|
JMP ($FFFC) ; RESET
|
|
end
|
|
//
|
|
// SET MEMORY TO VALUE
|
|
// MEMSET(ADDR, VALUE, SIZE)
|
|
// With optimizations from Peter Ferrie
|
|
//
|
|
asm memset
|
|
LDA ESTKL+2,X
|
|
STA DSTL
|
|
LDA ESTKH+2,X
|
|
STA DSTH
|
|
LDY ESTKL,X
|
|
BEQ +
|
|
INC ESTKH,X
|
|
LDY #$00
|
|
+ LDA ESTKH,X
|
|
BEQ SETMEX
|
|
SETMLPL CLC
|
|
LDA ESTKL+1,X
|
|
SETMLPH STA (DST),Y
|
|
DEC ESTKL,X
|
|
BEQ ++
|
|
- INY
|
|
BEQ +
|
|
-- BCS SETMLPL
|
|
SEC
|
|
LDA ESTKH+1,X
|
|
BCS SETMLPH
|
|
+ INC DSTH
|
|
BNE --
|
|
++ DEC ESTKH,X
|
|
BNE -
|
|
SETMEX INX
|
|
INX
|
|
RTS
|
|
end
|
|
//
|
|
// COPY MEMORY
|
|
// MEMCPY(DSTADDR, SRCADDR, SIZE)
|
|
//
|
|
asm memcpy
|
|
INX
|
|
INX
|
|
LDA ESTKL-2,X
|
|
ORA ESTKH-2,X
|
|
BEQ CPYMEX
|
|
LDA ESTKL-1,X
|
|
CMP ESTKL,X
|
|
LDA ESTKH-1,X
|
|
SBC ESTKH,X
|
|
BCC REVCPY
|
|
;
|
|
; FORWARD COPY
|
|
;
|
|
LDA ESTKL,X
|
|
STA DSTL
|
|
LDA ESTKH,X
|
|
STA DSTH
|
|
LDA ESTKL-1,X
|
|
STA SRCL
|
|
LDA ESTKH-1,X
|
|
STA SRCH
|
|
LDY ESTKL-2,X
|
|
BEQ FORCPYLP
|
|
INC ESTKH-2,X
|
|
LDY #$00
|
|
FORCPYLP LDA (SRC),Y
|
|
STA (DST),Y
|
|
INY
|
|
BNE +
|
|
INC DSTH
|
|
INC SRCH
|
|
+ DEC ESTKL-2,X
|
|
BNE FORCPYLP
|
|
DEC ESTKH-2,X
|
|
BNE FORCPYLP
|
|
RTS
|
|
;
|
|
; REVERSE COPY
|
|
;
|
|
REVCPY ;CLC
|
|
LDA ESTKL-2,X
|
|
ADC ESTKL,X
|
|
STA DSTL
|
|
LDA ESTKH-2,X
|
|
ADC ESTKH,X
|
|
STA DSTH
|
|
CLC
|
|
LDA ESTKL-2,X
|
|
ADC ESTKL-1,X
|
|
STA SRCL
|
|
LDA ESTKH-2,X
|
|
ADC ESTKH-1,X
|
|
STA SRCH
|
|
DEC DSTH
|
|
DEC SRCH
|
|
LDY #$FF
|
|
LDA ESTKL-2,X
|
|
BEQ REVCPYLP
|
|
INC ESTKH-2,X
|
|
REVCPYLP LDA (SRC),Y
|
|
STA (DST),Y
|
|
DEY
|
|
CPY #$FF
|
|
BNE +
|
|
DEC DSTH
|
|
DEC SRCH
|
|
+ DEC ESTKL-2,X
|
|
BNE REVCPYLP
|
|
DEC ESTKH-2,X
|
|
BNE REVCPYLP
|
|
CPYMEX RTS
|
|
end
|
|
//
|
|
// COPY FROM MAIN MEM TO AUX MEM.
|
|
//
|
|
// MEMXCPY(DST, SRC, SIZE)
|
|
//
|
|
asm memxcpy
|
|
LDA ESTKL+1,X
|
|
STA $3C
|
|
CLC
|
|
ADC ESTKL,X
|
|
STA $3E
|
|
LDA ESTKH+1,X
|
|
STA $3D
|
|
ADC ESTKH,X
|
|
STA $3F
|
|
LDA ESTKL+2,X
|
|
STA $42
|
|
LDA ESTKH+2,X
|
|
STA $43
|
|
STX ESP
|
|
BIT ROMEN
|
|
SEC
|
|
JSR $C311
|
|
BIT LCRDEN+LCBNK2
|
|
LDX ESP
|
|
INX
|
|
INX
|
|
RTS
|
|
end
|
|
asm crout
|
|
DEX
|
|
LDA #$0D
|
|
BNE +
|
|
; FALL THROUGH TO COUT
|
|
end
|
|
//
|
|
// CHAR OUT
|
|
// COUT(CHAR)
|
|
//
|
|
asm cout
|
|
LDA ESTKL,X
|
|
BIT $BF98
|
|
BMI +
|
|
JSR TOUPR
|
|
+ ORA #$80
|
|
BIT ROMEN
|
|
JSR $FDED
|
|
BIT LCRDEN+LCBNK2
|
|
RTS
|
|
end
|
|
//
|
|
// CHAR IN
|
|
// RDKEY()
|
|
//
|
|
asm cin
|
|
BIT ROMEN
|
|
JSR $FD0C
|
|
BIT LCRDEN+LCBNK2
|
|
DEX
|
|
LDY #$00
|
|
AND #$7F
|
|
STA ESTKL,X
|
|
STY ESTKH,X
|
|
RTS
|
|
end
|
|
//
|
|
// PRINT STRING
|
|
// PRSTR(STR)
|
|
//
|
|
asm prstr
|
|
LDY #$00
|
|
LDA ESTKL,X
|
|
STA SRCL
|
|
LDA ESTKH,X
|
|
STA SRCH
|
|
LDA (SRC),Y
|
|
BEQ ++
|
|
STA TMP
|
|
BIT ROMEN
|
|
- INY
|
|
LDA (SRC),Y
|
|
BIT $BF98
|
|
BMI +
|
|
JSR TOUPR
|
|
+ ORA #$80
|
|
JSR $FDED
|
|
CPY TMP
|
|
BNE -
|
|
BIT LCRDEN+LCBNK2
|
|
++ RTS
|
|
end
|
|
//
|
|
// PRINT BYTE
|
|
//
|
|
asm prbyte
|
|
LDA ESTKL,X
|
|
STX ESP
|
|
BIT ROMEN
|
|
JSR $FDDA
|
|
LDX ESP
|
|
BIT LCRDEN+LCBNK2
|
|
RTS
|
|
end
|
|
//
|
|
// PRINT WORD
|
|
//
|
|
asm prword
|
|
STX ESP
|
|
TXA
|
|
TAY
|
|
LDA ESTKH,Y
|
|
LDX ESTKL,Y
|
|
BIT ROMEN
|
|
JSR $F941
|
|
LDX ESP
|
|
BIT LCRDEN+LCBNK2
|
|
RTS
|
|
end
|
|
//
|
|
// READ STRING
|
|
// STR = RDSTR(PROMPTCHAR)
|
|
//
|
|
asm rdstr
|
|
LDA ESTKL,X
|
|
STA $33
|
|
STX ESP
|
|
BIT ROMEN
|
|
JSR $FD6A
|
|
STX $01FF
|
|
- LDA $01FF,X
|
|
AND #$7F
|
|
STA $01FF,X
|
|
DEX
|
|
BPL -
|
|
TXA
|
|
LDX ESP
|
|
STA ESTKL,X
|
|
LDA #$01
|
|
STA ESTKH,X
|
|
BIT LCRDEN+LCBNK2
|
|
RTS
|
|
end
|
|
asm uword_isge
|
|
LDA ESTKL+1,X
|
|
CMP ESTKL,X
|
|
LDA ESTKH+1,X
|
|
SBC ESTKH,X
|
|
LDA #$FF
|
|
ADC #$00
|
|
EOR #$FF
|
|
STA ESTKL+1,X
|
|
STA ESTKH+1,X
|
|
INX
|
|
RTS
|
|
end
|
|
asm uword_isle
|
|
LDA ESTKL,X
|
|
CMP ESTKL+1,X
|
|
LDA ESTKH,X
|
|
SBC ESTKH+1,X
|
|
LDA #$FF
|
|
ADC #$00
|
|
EOR #$FF
|
|
STA ESTKL+1,X
|
|
STA ESTKH+1,X
|
|
INX
|
|
RTS
|
|
end
|
|
asm uword_isgt
|
|
LDA ESTKL,X
|
|
CMP ESTKL+1,X
|
|
LDA ESTKH,X
|
|
SBC ESTKH+1,X
|
|
LDA #$FF
|
|
ADC #$00
|
|
STA ESTKL+1,X
|
|
STA ESTKH+1,X
|
|
INX
|
|
RTS
|
|
end
|
|
asm uword_islt
|
|
LDA ESTKL+1,X
|
|
CMP ESTKL,X
|
|
LDA ESTKH+1,X
|
|
SBC ESTKH,X
|
|
LDA #$FF
|
|
ADC #$00
|
|
STA ESTKL+1,X
|
|
STA ESTKH+1,X
|
|
INX
|
|
RTS
|
|
end
|
|
//
|
|
// Utility routines.
|
|
//
|
|
// A DCI string is one that has the high bit set for every character except the last.
|
|
// More efficient than C or Pascal strings.
|
|
//
|
|
//def dcitos(dci, str)
|
|
// byte len, c
|
|
// len = 0
|
|
// repeat
|
|
// c = (dci).[len]
|
|
// len = len + 1
|
|
// (str).[len] = c & $7F
|
|
// until !(c & $80)
|
|
// ^str = len
|
|
// return len
|
|
//end
|
|
asm dcitos
|
|
LDA ESTKL,X
|
|
STA DSTL
|
|
LDA ESTKH,X
|
|
STA DSTH
|
|
LDA ESTKL+1,X
|
|
STA SRCL
|
|
LDA ESTKH+1,X
|
|
STA SRCH
|
|
LDY #$00
|
|
- LDA (SRC),Y
|
|
CMP #$80
|
|
AND #$7F
|
|
INY
|
|
STA (DST),Y
|
|
BCS -
|
|
TYA
|
|
LDY #$00
|
|
STA (DST),Y
|
|
INX
|
|
STA ESTKL,X
|
|
STY ESTKH,X
|
|
RTS
|
|
end
|
|
//def stodci(str, dci)
|
|
// byte len, c
|
|
// len = ^str
|
|
// if len == 0
|
|
// return
|
|
// fin
|
|
// c = toupper((str).[len]) & $7F
|
|
// len = len - 1
|
|
// (dci).[len] = c
|
|
// while len
|
|
// c = toupper((str).[len]) | $80
|
|
// len = len - 1
|
|
// (dci).[len] = c
|
|
// loop
|
|
// return ^str
|
|
//end
|
|
asm stodci
|
|
LDA ESTKL,X
|
|
STA DSTL
|
|
LDA ESTKH,X
|
|
STA DSTH
|
|
LDA ESTKL+1,X
|
|
STA SRCL
|
|
LDA ESTKH+1,X
|
|
STA SRCH
|
|
INX
|
|
LDY #$00
|
|
LDA (SRC),Y
|
|
BEQ ++
|
|
TAY
|
|
LDA (SRC),Y
|
|
JSR TOUPR
|
|
BNE +
|
|
- LDA (SRC),Y
|
|
JSR TOUPR
|
|
ORA #$80
|
|
+ DEY
|
|
STA (DST),Y
|
|
BNE -
|
|
LDA (SRC),Y
|
|
++ STA ESTKL,X
|
|
STY ESTKH,X
|
|
RTS
|
|
end
|
|
asm toupper
|
|
LDA ESTKL,X
|
|
TOUPR AND #$7F
|
|
CMP #'a'
|
|
BCC +
|
|
CMP #'z'+1
|
|
BCS +
|
|
SBC #$1F
|
|
+ STA ESTKL,X
|
|
RTS
|
|
end
|
|
//
|
|
// Module symbols are entered into the symbol table
|
|
// pre-pended with a '#' to differentiate them
|
|
// from normal symbols.
|
|
//
|
|
//def modtosym(mod, dci)
|
|
// byte len, c
|
|
// (dci).0 = '#'|$80
|
|
// len = 0
|
|
// repeat
|
|
// c = (mod).[len]
|
|
// len = len + 1
|
|
// (dci).[len] = c
|
|
// until !(c & $80)
|
|
// return dci
|
|
//end
|
|
asm modtosym
|
|
LDA ESTKL+1,X
|
|
STA SRCL
|
|
LDA ESTKH+1,X
|
|
STA SRCH
|
|
LDA ESTKL,X
|
|
STA ESTKL+1,X
|
|
STA DSTL
|
|
LDA ESTKH,X
|
|
STA ESTKH+1,X
|
|
STA DSTH
|
|
INX
|
|
LDY #$00
|
|
LDA #'#'+$80
|
|
- STA (DST),Y
|
|
ASL
|
|
LDA (SRC),Y
|
|
INY
|
|
BCS -
|
|
RTS
|
|
end
|
|
//
|
|
// Lookup routines.
|
|
//
|
|
//def lookuptbl(dci, tbl)
|
|
// word match
|
|
// while ^tbl
|
|
// match = dci
|
|
// while ^tbl == ^match
|
|
// if !(^tbl & $80)
|
|
// return (tbl):1
|
|
// fin
|
|
// tbl = tbl + 1
|
|
// match = match + 1
|
|
// loop
|
|
// while (^tbl & $80)
|
|
// tbl = tbl + 1
|
|
// loop
|
|
// tbl = tbl + 3
|
|
// loop
|
|
// return 0
|
|
asm lookuptbl
|
|
LDA ESTKL,X
|
|
STA DSTL
|
|
LDA ESTKH,X
|
|
STA DSTH
|
|
LDA ESTKL+1,X
|
|
STA SRCL
|
|
LDA ESTKH+1,X
|
|
STA SRCH
|
|
LDY #$00
|
|
- LDA (DST),Y
|
|
BEQ +
|
|
CMP (SRC),Y
|
|
BNE ++
|
|
INY
|
|
ASL
|
|
BCS -
|
|
LDA (DST),Y
|
|
PHA
|
|
INY
|
|
LDA (DST),Y
|
|
TAY
|
|
PLA
|
|
+ INX
|
|
STA ESTKL,X
|
|
STY ESTKH,X
|
|
RTS
|
|
++ LDY #$00
|
|
-- LDA (DST),Y
|
|
INC DSTL
|
|
BEQ +
|
|
--- ASL
|
|
BCS --
|
|
LDA #$02
|
|
ADC DSTL
|
|
STA DSTL
|
|
BCC -
|
|
INC DSTH
|
|
BCS -
|
|
+ INC DSTH
|
|
BNE ---
|
|
end
|
|
//
|
|
// ProDOS routines
|
|
//
|
|
def getpfx(path)
|
|
byte params[3]
|
|
|
|
^path = 0
|
|
params.0 = 1
|
|
params:1 = path
|
|
perr = syscall($C7, @params)
|
|
return path
|
|
end
|
|
def setpfx(path)
|
|
byte params[3]
|
|
|
|
params.0 = 1
|
|
params:1 = path
|
|
perr = syscall($C6, @params)
|
|
return path
|
|
end
|
|
def open(path, buff)
|
|
byte params[6]
|
|
|
|
params.0 = 3
|
|
params:1 = path
|
|
params:3 = buff
|
|
params.5 = 0
|
|
perr = syscall($C8, @params)
|
|
return params.5
|
|
end
|
|
def close(refnum)
|
|
byte params[2]
|
|
|
|
params.0 = 1
|
|
params.1 = refnum
|
|
perr = syscall($CC, @params)
|
|
return perr
|
|
end
|
|
def read(refnum, buff, len)
|
|
byte params[8]
|
|
|
|
params.0 = 4
|
|
params.1 = refnum
|
|
params:2 = buff
|
|
params:4 = len
|
|
params:6 = 0
|
|
perr = syscall($CA, @params)
|
|
return params:6
|
|
end
|
|
//
|
|
// Heap routines.
|
|
//
|
|
def availheap
|
|
byte fp
|
|
return @fp - heap
|
|
end
|
|
def allocheap(size)
|
|
word addr
|
|
addr = heap
|
|
heap = heap + size
|
|
if systemflags & reshgr1
|
|
if uword_islt(addr, $4000) and uword_isgt(heap, $2000)
|
|
addr = $4000
|
|
heap = addr + size
|
|
fin
|
|
fin
|
|
if systemflags & reshgr2
|
|
if uword_islt(addr, $6000) and uword_isgt(heap, $4000)
|
|
addr = $6000
|
|
heap = addr + size
|
|
fin
|
|
fin
|
|
if uword_isge(heap, @addr)
|
|
return 0
|
|
fin
|
|
return addr
|
|
end
|
|
def allocalignheap(size, pow2, freeaddr)
|
|
word align, addr
|
|
if freeaddr
|
|
*freeaddr = heap
|
|
fin
|
|
align = (1 << pow2) - 1
|
|
addr = (heap | align) + 1
|
|
heap = addr + size
|
|
if uword_isge(heap, @addr)
|
|
return 0
|
|
fin
|
|
return addr
|
|
end
|
|
def markheap
|
|
return heap
|
|
end
|
|
def releaseheap(newheap)
|
|
heap = newheap
|
|
return @newheap - heap
|
|
end
|
|
def allocxheap(size)
|
|
word xaddr
|
|
xaddr = xheap
|
|
xheap = xheap + size
|
|
if systemflags & restxt1
|
|
if uword_isle(xaddr, $0800) and uword_isgt(xheap, $0400)
|
|
xaddr = $0800
|
|
xheap = xaddr + size
|
|
fin
|
|
fin
|
|
if systemflags & restxt2
|
|
if uword_isle(xaddr, $0C00) and uword_isgt(xheap, $0800)
|
|
xaddr = $0C00
|
|
xheap = xaddr + size
|
|
fin
|
|
fin
|
|
if systemflags & resxhgr1
|
|
if uword_isle(xaddr, $4000) and uword_isgt(xheap, $2000)
|
|
xaddr = $4000
|
|
xheap = xaddr + size
|
|
fin
|
|
fin
|
|
if systemflags & resxhgr2
|
|
if uword_isle(xaddr, $6000) and uword_isgt(xheap, $4000)
|
|
xaddr = $6000
|
|
xheap = xaddr + size
|
|
fin
|
|
fin
|
|
if uword_isge(xheap, $BF00)
|
|
return 0
|
|
fin
|
|
return xaddr
|
|
end
|
|
//
|
|
// Symbol table routines.
|
|
//
|
|
def lookupsym(sym)
|
|
return lookuptbl(sym, symtbl)
|
|
end
|
|
def addsym(sym, addr)
|
|
while ^sym & $80
|
|
^lastsym = ^sym
|
|
lastsym = lastsym + 1
|
|
sym = sym + 1
|
|
loop
|
|
lastsym->0 = ^sym
|
|
lastsym=>1 = addr
|
|
lastsym = lastsym + 3
|
|
^lastsym = 0
|
|
end
|
|
//
|
|
// Module routines.
|
|
//
|
|
def lookupmod(mod)
|
|
byte dci[17]
|
|
return lookuptbl(modtosym(mod, @dci), symtbl)
|
|
end
|
|
def lookupstrmod(str)
|
|
byte mod[17]
|
|
stodci(str, @mod)
|
|
return lookupmod(@mod)
|
|
end
|
|
def addmod(mod, addr)
|
|
byte dci[17]
|
|
return addsym(modtosym(mod, @dci), addr)
|
|
end
|
|
def lookupextern(esd, index)
|
|
word sym, addr
|
|
byte str[16]
|
|
while ^esd
|
|
sym = esd
|
|
esd = esd + dcitos(esd, @str)
|
|
if esd->0 & $10 and esd->1 == index
|
|
addr = lookupsym(sym)
|
|
if !addr
|
|
perr = $81
|
|
cout('?')
|
|
prstr(@str)
|
|
crout
|
|
fin
|
|
return addr
|
|
fin
|
|
esd = esd + 3
|
|
loop
|
|
return 0
|
|
end
|
|
def adddef(bank, addr, deflast)
|
|
word defentry
|
|
defentry = *deflast
|
|
*deflast = defentry + 5
|
|
if bank
|
|
defentry=>1 = $03DC // JSR $03DC (AUX MEM INTERP)
|
|
else
|
|
defentry=>1 = $03D6 // JSR $03D6 (MAIN MEM INTERP)
|
|
fin
|
|
defentry->0 = $20
|
|
defentry=>3 = addr
|
|
defentry->5 = 0 // NULL out next entry
|
|
return defentry
|
|
end
|
|
def lookupdef(addr, deftbl)
|
|
while deftbl->0 == $20
|
|
if deftbl=>3 == addr
|
|
return deftbl
|
|
fin
|
|
deftbl = deftbl + 5
|
|
loop
|
|
return 0
|
|
end
|
|
def loadmod(mod)
|
|
word refnum, rdlen, modsize, bytecode, defofst, defcnt, init, fixup
|
|
word addr, defaddr, modaddr, modfix, modend
|
|
word deftbl, deflast
|
|
word moddep, rld, esd, sym
|
|
byte defbank, str[16], filename[64]
|
|
byte header[128]
|
|
//
|
|
// Read the RELocatable module header (first 128 bytes)
|
|
//
|
|
dcitos(mod, @filename)
|
|
refnum = open(@filename, iobuffer)
|
|
if refnum > 0
|
|
rdlen = read(refnum, @header, 128)
|
|
modsize = header:0
|
|
moddep = @header.1
|
|
defofst = modsize
|
|
init = 0
|
|
if rdlen > 4 and header:2 == $DA7E // DAVE = magic number :-)
|
|
//
|
|
// This is an EXTended RELocatable (data+bytecode) module.
|
|
//
|
|
systemflags = header:4 | systemflags
|
|
defofst = header:6
|
|
defcnt = header:8
|
|
init = header:10
|
|
moddep = @header.12
|
|
//
|
|
// Load module dependencies.
|
|
//
|
|
while ^moddep
|
|
if !lookupmod(moddep)
|
|
close(refnum)
|
|
refnum = 0
|
|
if loadmod(moddep) < 0
|
|
return -perr
|
|
fin
|
|
fin
|
|
moddep = moddep + dcitos(moddep, @str)
|
|
loop
|
|
//
|
|
// Init def table.
|
|
//
|
|
deftbl = allocheap(defcnt * 5 + 1)
|
|
deflast = deftbl
|
|
^deflast = 0
|
|
if !refnum
|
|
//
|
|
// Reset read pointer.
|
|
//
|
|
refnum = open(@filename, iobuffer)
|
|
rdlen = read(refnum, @header, 128)
|
|
fin
|
|
fin
|
|
//
|
|
// Alloc heap space for relocated module (data + bytecode).
|
|
//
|
|
moddep = moddep + 1
|
|
modfix = moddep - @header.2 // Adjust to skip header
|
|
modsize = modsize - modfix
|
|
rdlen = rdlen - modfix - 2
|
|
modaddr = allocheap(modsize)
|
|
memcpy(modaddr, moddep, rdlen)
|
|
//
|
|
// Read in remainder of module into memory for fixups.
|
|
//
|
|
addr = modaddr//
|
|
repeat
|
|
addr = addr + rdlen
|
|
rdlen = read(refnum, addr, 4096)
|
|
until rdlen <= 0
|
|
close(refnum)
|
|
//
|
|
// Add module to symbol table.
|
|
//
|
|
addmod(mod, modaddr)
|
|
//
|
|
// Apply all fixups and symbol import/export.
|
|
//
|
|
modfix = modaddr - modfix
|
|
bytecode = defofst + modfix - MODADDR
|
|
modend = modaddr + modsize
|
|
rld = modend // Re-Locatable Directory
|
|
esd = rld // Extern+Entry Symbol Directory
|
|
while ^esd // Scan to end of ESD
|
|
esd = esd + 4
|
|
loop
|
|
esd = esd + 1
|
|
//
|
|
// Locate bytecode defs in appropriate bank.
|
|
//
|
|
if ^MACHID & $30 == $30
|
|
defbank = 1
|
|
defaddr = allocxheap(rld - bytecode)
|
|
modend = bytecode
|
|
else
|
|
defbank = 0
|
|
defaddr = bytecode
|
|
fin
|
|
//
|
|
// Run through the Re-Location Dictionary.
|
|
//
|
|
while ^rld
|
|
if ^rld == $02
|
|
//
|
|
// This is a bytcode def entry - add it to the def directory.
|
|
//
|
|
adddef(defbank, rld=>1 - defofst + defaddr, @deflast)
|
|
else
|
|
addr = rld=>1 + modfix
|
|
if uword_isge(addr, modaddr) // Skip fixups to header
|
|
if ^rld & $80 // WORD sized fixup.
|
|
fixup = *addr
|
|
else // BYTE sized fixup.
|
|
fixup = ^addr
|
|
fin
|
|
if ^rld & $10 // EXTERN reference.
|
|
fixup = fixup + lookupextern(esd, rld->3)
|
|
else // INTERN fixup.
|
|
fixup = fixup + modfix - MODADDR
|
|
if uword_isge(fixup, bytecode)
|
|
//
|
|
// Bytecode address - replace with call def directory.
|
|
//
|
|
fixup = lookupdef(fixup - bytecode + defaddr, deftbl)
|
|
fin
|
|
fin
|
|
if ^rld & $80 // WORD sized fixup.
|
|
*addr = fixup
|
|
else // BYTE sized fixup.
|
|
^addr = fixup
|
|
fin
|
|
fin
|
|
fin
|
|
rld = rld + 4
|
|
loop
|
|
//
|
|
// Run through the External/Entry Symbol Directory.
|
|
//
|
|
while ^esd
|
|
sym = esd
|
|
esd = esd + dcitos(esd, @str)
|
|
if ^esd & $08
|
|
//
|
|
// EXPORT symbol - add it to the global symbol table.
|
|
//
|
|
addr = esd=>1 + modfix - MODADDR
|
|
if uword_isge(addr, bytecode)
|
|
//
|
|
// Use the def directory address for bytecode.
|
|
//
|
|
addr = lookupdef(addr - bytecode + defaddr, deftbl)
|
|
fin
|
|
addsym(sym, addr)
|
|
fin
|
|
esd = esd + 3
|
|
loop
|
|
if defbank
|
|
//
|
|
// Move bytecode to AUX bank.
|
|
//
|
|
memxcpy(defaddr, bytecode, modsize - (bytecode - modaddr))
|
|
fin
|
|
fin
|
|
if perr
|
|
return -perr
|
|
fin
|
|
//
|
|
// Call init routine if it exists.
|
|
//
|
|
fixup = 0 // This is repurposed for the return code
|
|
if init
|
|
fixup = adddef(defbank, init - defofst + defaddr, @deflast)()
|
|
if fixup < modinitkeep
|
|
//
|
|
// Free init routine unless initkeep
|
|
//
|
|
if defbank
|
|
xheap = init - defofst + defaddr
|
|
else
|
|
modend = init - defofst + defaddr
|
|
fin
|
|
if fixup < 0
|
|
perr = -fixup
|
|
fin
|
|
else
|
|
fixup = fixup & ~modinitkeep
|
|
fin
|
|
fin
|
|
//
|
|
// Free up the end-of-module in main memory.
|
|
//
|
|
releaseheap(modend)
|
|
return fixup
|
|
end
|
|
//
|
|
// Command mode
|
|
//
|
|
def volumes
|
|
byte params[4]
|
|
word strbuf
|
|
byte i
|
|
|
|
params.0 = 2
|
|
params.1 = 0
|
|
params:2 = databuff
|
|
perr = syscall($C5, @params)
|
|
strbuf = databuff
|
|
for i = 0 to 15
|
|
^strbuf = ^strbuf & $0F
|
|
if ^strbuf
|
|
cout('/')
|
|
prstr(strbuf)
|
|
crout()
|
|
fin
|
|
strbuf = strbuf + 16
|
|
next
|
|
end
|
|
def catalog(optpath)
|
|
byte path[64]
|
|
byte refnum
|
|
byte firstblk
|
|
byte entrylen, entriesblk
|
|
byte i, type, len
|
|
word entry, filecnt
|
|
|
|
if ^optpath
|
|
memcpy(@path, optpath, ^optpath + 1)
|
|
else
|
|
getpfx(@path)
|
|
prstr(@path)
|
|
crout()
|
|
fin
|
|
refnum = open(@path, iobuffer)
|
|
if perr
|
|
return perr
|
|
fin
|
|
firstblk = 1
|
|
repeat
|
|
if read(refnum, databuff, 512) == 512
|
|
entry = databuff + 4
|
|
if firstblk
|
|
entrylen = databuff.$23
|
|
entriesblk = databuff.$24
|
|
filecnt = databuff:$25
|
|
entry = entry + entrylen
|
|
fin
|
|
for i = firstblk to entriesblk
|
|
type = ^entry
|
|
if type
|
|
len = type & $0F
|
|
^entry = len
|
|
prstr(entry)
|
|
if type & $F0 == $D0 // Is it a directory?
|
|
cout('/')
|
|
len = len + 1
|
|
elsif entry->$10 == $FF
|
|
cout('-')
|
|
len = len + 1
|
|
elsif entry->$10 == $FE
|
|
cout('+')
|
|
len = len + 1
|
|
fin
|
|
for len = 19 - len downto 0
|
|
cout(' ')
|
|
next
|
|
filecnt = filecnt - 1
|
|
fin
|
|
entry = entry + entrylen
|
|
next
|
|
firstblk = 0
|
|
else
|
|
filecnt = 0
|
|
fin
|
|
until !filecnt
|
|
close(refnum)
|
|
crout()
|
|
return 0
|
|
end
|
|
def stripchars(strptr)
|
|
while ^strptr and ^(strptr + 1) > ' '
|
|
memcpy(strptr + 1, strptr + 2, ^strptr)
|
|
^strptr = ^strptr - 1
|
|
loop
|
|
return ^strptr
|
|
end
|
|
def stripspaces(strptr)
|
|
while ^strptr and ^(strptr + ^strptr) <= ' '
|
|
^strptr = ^strptr - 1
|
|
loop
|
|
while ^strptr and ^(strptr + 1) <= ' '
|
|
memcpy(strptr + 1, strptr + 2, ^strptr)
|
|
^strptr = ^strptr - 1
|
|
loop
|
|
end
|
|
def striptrail(strptr)
|
|
byte i
|
|
|
|
for i = 1 to ^strptr
|
|
if ^(strptr + i) <= ' '
|
|
^strptr = i - 1
|
|
return
|
|
fin
|
|
next
|
|
end
|
|
def parsecmd(strptr)
|
|
byte cmd
|
|
|
|
cmd = 0
|
|
stripspaces(strptr)
|
|
if ^strptr
|
|
cmd = ^(strptr + 1)
|
|
memcpy(strptr + 1, strptr + 2, ^strptr)
|
|
^strptr = ^strptr - 1
|
|
fin
|
|
stripspaces(strptr)
|
|
return cmd
|
|
end
|
|
def resetmemfiles
|
|
//
|
|
// Close all files
|
|
//
|
|
^$BFD8 = 0
|
|
close(0)
|
|
//
|
|
// Set memory bitmap
|
|
//
|
|
memset($BF58, 0, 24)
|
|
^$BF58 = $CF
|
|
^$BF6F = $01
|
|
end
|
|
def execsys(sysfile)
|
|
byte refnum
|
|
word len
|
|
|
|
if ^sysfile
|
|
memcpy($280, sysfile, ^sysfile + 1)
|
|
striptrail(sysfile)
|
|
refnum = open(sysfile, iobuffer)
|
|
if refnum
|
|
len = read(refnum, databuff, $FFFF)
|
|
resetmemfiles()
|
|
if len
|
|
memcpy(sysfile, $280, ^$280 + 1)
|
|
if stripchars(sysfile) and ^$2000 == $4C and *$2003 == $EEEE
|
|
stripspaces(sysfile)
|
|
if ^$2005 >= ^sysfile + 1
|
|
memcpy($2006, sysfile, ^sysfile + 1)
|
|
fin
|
|
fin
|
|
striptrail($280)
|
|
exec()
|
|
fin
|
|
fin
|
|
fin
|
|
end
|
|
def execmod(modfile)
|
|
byte moddci[17]
|
|
word saveheap, savexheap, savesym, saveflags
|
|
|
|
perr = 1
|
|
if stodci(modfile, @moddci)
|
|
saveheap = heap
|
|
savexheap = xheap
|
|
savesym = lastsym
|
|
saveflags = systemflags
|
|
if loadmod(@moddci) < modkeep
|
|
lastsym = savesym
|
|
xheap = savexheap
|
|
heap = saveheap
|
|
fin
|
|
^lastsym = 0
|
|
systemflags = saveflags
|
|
fin
|
|
return -perr
|
|
end
|
|
//
|
|
// Get heap start.
|
|
//
|
|
heap = *freemem
|
|
//
|
|
// Init symbol table.
|
|
//
|
|
stodci(@syslibstr, heap)
|
|
addmod(heap, @version)
|
|
while *syslibsym
|
|
stodci(syslibsym=>0, heap)
|
|
addsym(heap, syslibsym=>2)
|
|
syslibsym = syslibsym + 4
|
|
loop
|
|
//
|
|
// Try to load autorun.
|
|
//
|
|
autorun = open(@autorun, iobuffer)
|
|
if autorun > 0
|
|
cmdln = read(autorun, @syslibstr, 128)
|
|
close(autorun)
|
|
else
|
|
//
|
|
// Print some startup info.
|
|
//
|
|
prstr("PLASMA ")
|
|
prbyte(version.1)
|
|
cout('.')
|
|
prbyte(version.0)
|
|
crout
|
|
prstr("MEM FREE:$")
|
|
prword(availheap)
|
|
crout
|
|
fin
|
|
perr = 0
|
|
while 1
|
|
if cmdln
|
|
when toupper(parsecmd(@cmdln))
|
|
is 'Q'
|
|
reboot()
|
|
break
|
|
is 'C'
|
|
catalog(@cmdln)
|
|
break
|
|
is 'P'
|
|
setpfx(@cmdln)
|
|
break
|
|
is 'V'
|
|
volumes()
|
|
break
|
|
is '-'
|
|
execsys(@cmdln)
|
|
break
|
|
is '+'
|
|
execmod(@cmdln)
|
|
break
|
|
otherwise
|
|
cout('?')
|
|
wend
|
|
if perr
|
|
prstr("ERR:$")
|
|
prbyte(perr)
|
|
perr = 0
|
|
else
|
|
prstr("OK")
|
|
fin
|
|
crout()
|
|
fin
|
|
prstr(getpfx(@prefix))
|
|
memcpy(@cmdln, rdstr($BA), 128)
|
|
loop
|
|
done
|