mirror of
https://github.com/dschmenk/PLASMA.git
synced 2026-03-12 01:41:40 +00:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7aaba1f9ef | ||
|
|
a61da48e5d | ||
|
|
45489b3ab8 | ||
|
|
81e40c4c7f | ||
|
|
6ff3cc2673 | ||
|
|
f964099c24 | ||
|
|
54ecb3eec7 | ||
|
|
bb97fe6353 | ||
|
|
9e441de1c2 | ||
|
|
3d337f4fa8 | ||
|
|
15e4013f97 | ||
|
|
5f1656b6a1 | ||
|
|
9809c2b5b2 | ||
|
|
c0ddb5d197 | ||
|
|
e3606f3f64 |
BIN
PLASMA-BLD1.PO
BIN
PLASMA-BLD1.PO
Binary file not shown.
BIN
PLASMA-SYS1.PO
BIN
PLASMA-SYS1.PO
Binary file not shown.
@@ -1,5 +1,5 @@
|
||||
# 3/13/2018 PLASMA 1.1 Available!
|
||||
[Download and read the Release Notes](https://github.com/dschmenk/PLASMA/blob/master/doc/Version%201.1.md)
|
||||
# 4/29/2018 PLASMA 1.2 Available!
|
||||
[Download and read the Release Notes](https://github.com/dschmenk/PLASMA/blob/master/doc/Version%201.2.md)
|
||||
|
||||
# The PLASMA Programming Language
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# PLASMA Version 1.1
|
||||
# PLASMA Version 1.2
|
||||
|
||||
Welcome to PLASMA: the Grand Unifying Platform for the Apple 1, ][, and ///.
|
||||
|
||||
Download the four disk images (three if you don't plan to boot an Apple ///):
|
||||
|
||||
[PLASMA 1.1 System and ProDOS Boot](https://github.com/dschmenk/PLASMA/blob/master/PLASMA-SYS1.PO?raw=true)
|
||||
[PLASMA 1.2 System and ProDOS Boot](https://github.com/dschmenk/PLASMA/blob/ver-1/PLASMA-SYS1.PO?raw=true)
|
||||
|
||||
[PLASMA 1.1 Build Tools](https://github.com/dschmenk/PLASMA/blob/master/PLASMA-BLD1.PO?raw=true)
|
||||
[PLASMA 1.2 Build Tools](https://github.com/dschmenk/PLASMA/blob/ver-1/PLASMA-BLD1.PO?raw=true)
|
||||
|
||||
[PLASMA 1.1 Demos](https://github.com/dschmenk/PLASMA/blob/master/PLASMA-DEM1.PO?raw=true)
|
||||
[PLASMA 1.2 Demos](https://github.com/dschmenk/PLASMA/blob/ver-1/PLASMA-DEM1.PO?raw=true)
|
||||
|
||||
[PLASMA 1.1 Apple /// SOS Boot ](https://github.com/dschmenk/PLASMA/blob/master/PLASMA-SOS1.PO?raw=true)
|
||||
[PLASMA 1.2 Apple /// SOS Boot ](https://github.com/dschmenk/PLASMA/blob/ver-1/PLASMA-SOS1.PO?raw=true)
|
||||
|
||||
PLASMA can be run from floppies, System in Drive 1, and Build or Demos in Drive 2. Mass storage is the recommended installation that looks like (replacing HARDISK with your volume name of choice):
|
||||
|
||||
@@ -98,6 +98,16 @@ There is a [YouTube playlist](https://www.youtube.com/playlist?list=PLlPKgUMQbJ7
|
||||
|
||||
- The documentation is sparse and incomplete. Yep, could use your help...
|
||||
|
||||
# Changes in PLASMA for 1.2
|
||||
|
||||
1. Add TFTPD TFTP server
|
||||
|
||||
2. Fix Uthernet 1 driver
|
||||
|
||||
3. Add mouse module
|
||||
|
||||
4. Fix IRQ issues for interrupt driven mouse driver
|
||||
|
||||
# Changes in PLASMA for 1.1
|
||||
|
||||
1. All known bugs are fixed
|
||||
32
src/inc/mouse.plh
Normal file
32
src/inc/mouse.plh
Normal file
@@ -0,0 +1,32 @@
|
||||
import mouse
|
||||
//
|
||||
// Status bits
|
||||
//
|
||||
const BUTTON_DOWN = $80
|
||||
const BUTTON_LAST_DOWN = $40
|
||||
const MOUSE_MOVED = $20
|
||||
const VBL_INT = $08
|
||||
const BUTTON_INT = $04
|
||||
const MOVE_INT = $02
|
||||
//
|
||||
// Mode bits
|
||||
//
|
||||
const VBL_INT_ENABLE = $08
|
||||
const BUTTON_INT_ENABLE= $04
|
||||
const MOVE_INT_ENABLE = $02
|
||||
const MOUSE_ENABLE = $01
|
||||
//
|
||||
// Mouse API
|
||||
//
|
||||
struc t_mouse
|
||||
word chkVBL
|
||||
word chkMouse
|
||||
word readMouse // readMouse()#3
|
||||
word setMouse // setMouse(mode)
|
||||
word clearMouse
|
||||
word posMouse // posMouse(x, y)
|
||||
word clampMouse // clampMouse(xMin, xMax, yMin, yMax)
|
||||
word homeMouse
|
||||
word detachMouse
|
||||
end
|
||||
end
|
||||
583
src/libsrc/apple/mouse.pla
Normal file
583
src/libsrc/apple/mouse.pla
Normal file
@@ -0,0 +1,583 @@
|
||||
include "inc/cmdsys.plh"
|
||||
//
|
||||
// Mouse driver interface
|
||||
//
|
||||
predef chkVbl, chkMouse, readMouse#3, setMouse(mode), clearMouse, posMouse(x, y), clampMouse(xMin, xMax, yMin, yMax), homeMouse, detachMouse
|
||||
word = @chkVbl, @chkMouse, @readMouse, @setMouse, @clearMouse, @posMouse, @clampMouse, @homeMouse, @detachMouse
|
||||
word rom
|
||||
byte params[]
|
||||
byte slot, index, page
|
||||
word setMouseFW
|
||||
byte vblDiv, vblInt, mouInt, bttnPrev
|
||||
asm equates
|
||||
!SOURCE "vmsrc/plvmzp.inc"
|
||||
end
|
||||
//
|
||||
// Serve Mouse/VBL IRQ
|
||||
//
|
||||
asm serviceMouse#0
|
||||
VBLINT = $400 ; DUMMY VALUES TO BE FIXED-UP
|
||||
MOUINT = $401
|
||||
LASTBTTN= $402
|
||||
CLD
|
||||
JSR $C400
|
||||
BCC +
|
||||
RTS ; NOT MOUSE INT
|
||||
+ LDY $0778+4 ; CHECK MOUSE INT CAUSE
|
||||
TYA ; WAS IT VBL?
|
||||
AND #$08
|
||||
BEQ + ; NOPE, MOVE OR BUTTON
|
||||
end
|
||||
asm vblEvent
|
||||
INC VBLINT ; INC VBL EVENT
|
||||
+ TYA ; MOUSE MOVE OR BUTTON ACTIVE
|
||||
AND #$82
|
||||
end
|
||||
asm bttnEvent
|
||||
EOR LASTBTTN
|
||||
BEQ +
|
||||
end
|
||||
asm mouseEvent
|
||||
INC MOUINT ; INC MOUSE EVENT
|
||||
+ TYA
|
||||
AND #$80
|
||||
end
|
||||
asm updateBttn
|
||||
STA LASTBTTN
|
||||
end
|
||||
asm updateMouse
|
||||
LDX #$C4
|
||||
LDY #$40
|
||||
JMP $C400 ; IIGS REQUIRES THIS HAPPEN IN IRQ
|
||||
end
|
||||
asm serviceCYA#0
|
||||
CLC
|
||||
RTS
|
||||
end
|
||||
//
|
||||
// Check for VBL (timer) and Mouse events (atomic read and reset)
|
||||
//
|
||||
asm chkEvt(addr)
|
||||
LDA ESTKL,X
|
||||
STA ESTKH-1,X
|
||||
SEI
|
||||
LDA (ESTKH-1,X) ; READ INT COUNT
|
||||
TAY
|
||||
LDA #$00
|
||||
STA (ESTKH-1,X) ; CLEAR INT COUNT
|
||||
CLI
|
||||
STY ESTKL,X ; RETURN INT COUNT
|
||||
STA ESTKH,X
|
||||
RTS
|
||||
end
|
||||
asm readMouse#3
|
||||
LDY #$04
|
||||
DEX
|
||||
DEX
|
||||
DEX
|
||||
PHP
|
||||
SEI
|
||||
LDA $0478,Y
|
||||
STA ESTKL+2,X
|
||||
LDA $0578,Y
|
||||
STA ESTKH+2,X
|
||||
LDA $04F8,Y
|
||||
STA ESTKL+1,X
|
||||
LDA $05F8,Y
|
||||
STA ESTKH+1,X
|
||||
LDA $0778,Y
|
||||
STA ESTKL,X
|
||||
LDA #$00
|
||||
STA ESTKH,X
|
||||
PLP
|
||||
RTS
|
||||
end
|
||||
//
|
||||
// Convert VBL interrupts into millisecond timer increment
|
||||
//
|
||||
def chkVblTimer
|
||||
byte count
|
||||
word msec
|
||||
|
||||
msec = 0
|
||||
count = chkEvt(@vblInt)
|
||||
while count
|
||||
if vblDiv & 2
|
||||
msec = msec + 16
|
||||
vblDiv = 0
|
||||
else
|
||||
msec = msec + 17
|
||||
vblDiv++
|
||||
fin
|
||||
count--
|
||||
loop
|
||||
return msec
|
||||
end
|
||||
//
|
||||
// Check for VBL/Mouse interrupt events
|
||||
//
|
||||
def chkVbl
|
||||
return chkEvt(@vblInt)
|
||||
end
|
||||
def chkMouse
|
||||
return chkEvt(@mouInt)
|
||||
end
|
||||
//
|
||||
// Mouse routines
|
||||
//
|
||||
def setMouse(mode)
|
||||
return call(setMouseFW, mode, slot, page, $04)
|
||||
end
|
||||
def clearMouse
|
||||
return call(rom + rom->$15, $00, slot, page, $04) // clearMouseFW
|
||||
end
|
||||
def posMouse(x, y)
|
||||
//
|
||||
// Fill screen holes
|
||||
//
|
||||
^($0478 + index) = x
|
||||
^($0578 + index) = x >> 8
|
||||
^($04F8 + index) = y
|
||||
^($05F8 + index) = y >> 8
|
||||
return call(rom + rom->$16, $00, slot, page, $04) // posMouseFW
|
||||
end
|
||||
def clampMouse(xMin, xMax, yMin, yMax)
|
||||
^$0478 = xMin
|
||||
^$0578 = xMin >> 8
|
||||
^$04F8 = xMax
|
||||
^$05F8 = xMax >> 8
|
||||
call(rom + rom->$17, $00, slot, page, $04) // clampMouseFW
|
||||
^$0478 = yMin
|
||||
^$0578 = yMin >> 8
|
||||
^$04F8 = yMax
|
||||
^$05F8 = yMax >> 8
|
||||
return call(rom + rom->$17, $01, slot, page, $04)) // clampMouseFW
|
||||
end
|
||||
def homeMouse
|
||||
return call(rom + rom->$18, $00, slot, page, $04) // homeMouseFW
|
||||
end
|
||||
//
|
||||
// Detach mouse from interrupts
|
||||
//
|
||||
def detachMouse
|
||||
setMouse(0)
|
||||
params.0 = 1
|
||||
params.1 = 0
|
||||
return syscall($41, @params)
|
||||
end
|
||||
//
|
||||
// Identify Mouse card/slot and initialize
|
||||
//
|
||||
for rom = $C100 to $C700 step $0100
|
||||
if rom->5 == $38 and rom->7 == $18 and rom->11 == $01 and rom->12 == $20
|
||||
puts("Found Mouse in slot #"); putc('0' + ((rom >> 8) & $07)); putln
|
||||
//
|
||||
// Hook mouse IRQ handler into ProDOS IRQ chain
|
||||
//
|
||||
params.0 = 2
|
||||
params.1 = 0
|
||||
params:2 = @serviceMouse
|
||||
syscall($40, @params)
|
||||
//
|
||||
// Hook CYA IRQ handler into ProDOS IRQ chain
|
||||
//
|
||||
params.0 = 2
|
||||
params.1 = 3
|
||||
params:2 = @serviceCYA
|
||||
syscall($40, @params)
|
||||
//
|
||||
// Set values
|
||||
//
|
||||
slot = rom >> 8
|
||||
index = slot & $07
|
||||
page = index << 4
|
||||
setMouseFW = rom + rom->$12
|
||||
//
|
||||
// Fix-up IRQ routine
|
||||
//
|
||||
serviceMouse:2 = rom + rom->$13 // serveMouseFW
|
||||
serviceMouse:8 = $0778+index
|
||||
vblEvent:1 = @vblInt
|
||||
bttnEvent:1 = @bttnPrev
|
||||
mouseEvent:1 = @mouInt
|
||||
updateBttn:1 = @bttnPrev
|
||||
updateMouse.1 = slot
|
||||
updateMouse.3 = page
|
||||
updateMouse:5 = rom + rom->$14 // readMouseFW
|
||||
readMouse.1 = index
|
||||
call(rom + rom->$19, $00, slot, page, $04) // initMouseFW
|
||||
return modkeep
|
||||
fin
|
||||
next
|
||||
//
|
||||
// Not found
|
||||
//
|
||||
return -1
|
||||
done
|
||||
|
||||
What follows is the relevant parts to the mouse driver for VM02
|
||||
|
||||
CHKMOUSE: LDX #$20 ; LOOK FOR MOUSE
|
||||
LDA #$01
|
||||
JSR SCAN_SLOTS
|
||||
BCS NOMOUSE
|
||||
PHA ; SAVE SLOT
|
||||
LDY #$13
|
||||
LDA (TMPTR),Y
|
||||
STA SERVEMOUSE+1 ; FIXUP IRQ HANDLER
|
||||
STX SERVEMOUSE+2
|
||||
LDY #$14
|
||||
LDA (TMPTR),Y
|
||||
STA READMOUSE+1 ; FIXUP IRQ HANDLER
|
||||
STX READMOUSE+2
|
||||
TXA
|
||||
AND #$07
|
||||
STA MOUSE_SLOT
|
||||
TAY
|
||||
JSR MOUSE_INIT ; MAKE SURE MOUSE IS OFF, INTS OFF
|
||||
LDA WARM_INIT
|
||||
BNE :+
|
||||
JSR PUTS
|
||||
.ASCIIZ "Mouse in slot #"
|
||||
LDA MOUSE_SLOT
|
||||
JSR PRBYTE
|
||||
JSR CROUT
|
||||
: PLA
|
||||
TAY
|
||||
LDA #<MOUSE_DRIVER ; LOAD MOUSE DRIVER
|
||||
LDX #>MOUSE_DRIVER
|
||||
JSR LOAD_DRIVER
|
||||
;
|
||||
; SCAN SLOTS FOR MATCHING CARD ID
|
||||
; ENTRY: A = START SLOT SCAN
|
||||
; X = CARD ID
|
||||
; EXIT: A = SLOT # :: C = 0
|
||||
; X = SLOT PAGE
|
||||
;
|
||||
SCAN_SLOTS: ORA #$C0
|
||||
STA TMPTR+1
|
||||
LDA #$00
|
||||
STA TMPTR
|
||||
CHKSIG: LDY #$05
|
||||
LDA (TMPTR),Y
|
||||
CMP #$38 ; LOOK FOR PASCAL COMPAT SIG
|
||||
BNE :+
|
||||
LDY #$07
|
||||
LDA (TMPTR),Y
|
||||
CMP #$18
|
||||
BNE :+
|
||||
LDY #$0B
|
||||
LDA (TMPTR),Y
|
||||
CMP #$01
|
||||
BNE :+
|
||||
LDY #$0C
|
||||
TXA ; LOOK FOR MATCHING ID
|
||||
CMP (TMPTR),Y
|
||||
BNE :+
|
||||
LDA TMPTR+1
|
||||
TAX
|
||||
AND #$07
|
||||
CLC
|
||||
RTS
|
||||
: INC TMPTR+1
|
||||
LDA TMPTR+1
|
||||
CMP #$C8
|
||||
BCC CHKSIG
|
||||
SEC
|
||||
RTS
|
||||
|
||||
;*
|
||||
;* TURN VBL INTS ON AFTER INIT
|
||||
;*
|
||||
VBL_INIT: LDA MOUSE_SLOT
|
||||
BEQ NOVBL
|
||||
ASL
|
||||
TAX
|
||||
LSR
|
||||
ORA #MOUSECTL_CALLFW
|
||||
TAY
|
||||
SEI ; TURN OFF INTERRUPTS
|
||||
LDA LINK_DEVCTRL,X
|
||||
STA CALLVBLPROC+1
|
||||
LDA LINK_DEVCTRL+1,X
|
||||
STA CALLVBLPROC+2
|
||||
LDA #$08 ; TURN MOUSE OFF, LEAVE VBL ON
|
||||
LDX #$12
|
||||
CALLVBLPROC: JSR $0000
|
||||
CLI ; BACK ON
|
||||
LDA WARM_INIT
|
||||
BNE NOVBL
|
||||
JSR PUTSLN
|
||||
.ASCIIZ "VBlank timer active"
|
||||
NOVBL: RTS
|
||||
|
||||
JSR PRODOS
|
||||
.BYTE $40 ; ALLOC INTERRUPT
|
||||
.ADDR ALLOCINTPARMS
|
||||
.IFDEF DEBUG
|
||||
BCC :+
|
||||
JSR PUTSLN
|
||||
.ASCIIZ "FAILED TO ALLOCATE INTERRUPT"
|
||||
:
|
||||
.ENDIF
|
||||
RTS
|
||||
ALLOCINTPARMS: .BYTE $02
|
||||
.BYTE $00 ; INT NUM
|
||||
.ADDR IO_INTERRUPT ; INT CODE
|
||||
|
||||
;*
|
||||
;* I/O INTERRUPT ROUTINE
|
||||
;*
|
||||
IO_INTERRUPT: CLD
|
||||
LDY #$02 ; SLOT #1 * 2
|
||||
FNDIRQPROC: LDA LINK_DEVIRQ+1,Y
|
||||
BEQ NXTIRQPROC
|
||||
STA CALLIRQPROC+2
|
||||
LDA LINK_DEVIRQ,Y
|
||||
STA CALLIRQPROC+1
|
||||
TYA
|
||||
LSR
|
||||
PHA
|
||||
CALLIRQPROC: JSR $0000
|
||||
BCS :+
|
||||
PLA
|
||||
TAY
|
||||
PHA
|
||||
JSR THREAD_NOTIFYIO
|
||||
: PLA
|
||||
ASL
|
||||
TAY
|
||||
NXTIRQPROC: INY
|
||||
INY
|
||||
CPY #$10
|
||||
BCC FNDIRQPROC
|
||||
CLC
|
||||
RTS
|
||||
|
||||
;*
|
||||
;* MOUSE DEVICE DRIVER
|
||||
;*
|
||||
MOUSE_INIT: ORA #$C0
|
||||
STA XREGMOUSE1+1
|
||||
STA XREGMOUSE2+1
|
||||
ASL
|
||||
ASL
|
||||
ASL
|
||||
ASL
|
||||
STA YREGMOUSE1+1
|
||||
STA YREGMOUSE2+1
|
||||
LDA #$00
|
||||
PHA ; DISABLE ALL MOUSE INTS
|
||||
LDX #$12 ; FW INDEX FOR SETMOUSE
|
||||
BNE CALLMOUSEFW
|
||||
MOUSE_DRIVER:
|
||||
MOUSE_DRVR_SZ: .WORD MOUSE_DRVR_END - MOUSE_DRVR_START
|
||||
MOUSE_READ_OFS: .WORD MOUSE_READ - MOUSE_DRVR_START
|
||||
MOUSE_WRITE_OFS: .WORD MOUSE_WRITE - MOUSE_DRVR_START
|
||||
MOUSE_CTRL_OFS: .WORD MOUSE_CTRL - MOUSE_DRVR_START
|
||||
MOUSE_IRQ_OFS: .WORD MOUSE_IRQ - MOUSE_DRVR_START
|
||||
MOUSE_DRVR_START:
|
||||
MOUSE_READ:
|
||||
MOUSE_WRITE: SEC
|
||||
RTS
|
||||
MOUSE_X: .WORD $0000
|
||||
MOUSE_Y: .WORD $0000
|
||||
MOUSE_STATUS: .BYTE $00
|
||||
MOUSE_CTRL: PHA
|
||||
TYA
|
||||
AND #$F8 ; MASK OFF SLOT #
|
||||
CMP #MOUSECTL_CALLFW
|
||||
BNE :+
|
||||
CALLMOUSEFW: STX OPADDR
|
||||
XREGMOUSE2: LDX #$C4
|
||||
STX OPADDR+1
|
||||
LDY #$00
|
||||
LDA (OPADDR),Y ; GET ENTRYPOINT OFFSET
|
||||
STA OPADDR
|
||||
YREGMOUSE2: LDY #$40
|
||||
PLA
|
||||
SEI
|
||||
JMP (OPADDR) ; CALL FIXED UP FUNCTION POINTER
|
||||
: CMP #MOUSECTL_READMOUSE ; COPY MOUSE STATUS/POSITION INTO EASILY ACCESSIBLE MEMORY
|
||||
BNE :+
|
||||
PLA
|
||||
TYA
|
||||
AND #$07
|
||||
TAX ; SAVE MOUSE PARAMETERS
|
||||
ASL
|
||||
TAY
|
||||
LDA LINK_DEVREAD,Y
|
||||
STA TMPTR
|
||||
LDA LINK_DEVREAD+1,Y
|
||||
STA TMPTR+1
|
||||
SEI
|
||||
LDY #$02
|
||||
LDA $0478,X
|
||||
STA (TMPTR),Y
|
||||
PHA
|
||||
INY
|
||||
LDA $0578,X
|
||||
STA (TMPTR),Y
|
||||
INY
|
||||
LDA $04F8,X
|
||||
STA (TMPTR),Y
|
||||
PHA
|
||||
INY
|
||||
LDA $05F8,X
|
||||
STA (TMPTR),Y
|
||||
INY
|
||||
LDA $0778,X
|
||||
STA (TMPTR),Y
|
||||
STA TMP
|
||||
PLA
|
||||
TAY
|
||||
PLA
|
||||
TAX
|
||||
LDA TMP
|
||||
RTS
|
||||
: CMP #MOUSECTL_CLAMPX
|
||||
BEQ :+
|
||||
CMP #MOUSECTL_CLAMPY
|
||||
BNE :++
|
||||
: PLA
|
||||
STA $04F8
|
||||
STX $05F8
|
||||
LDA #$00
|
||||
STA $0478
|
||||
STA $0578
|
||||
TYA
|
||||
LSR
|
||||
LSR
|
||||
LSR
|
||||
AND #$01
|
||||
PHA
|
||||
LDX #$17 ; FW INDEX FOR CLAMPMOUSE
|
||||
BNE CALLMOUSEFW
|
||||
SETMOUSE: PHA
|
||||
LDX #$12 ; FW INDEX FOR SETMOUSE
|
||||
BNE CALLMOUSEFW
|
||||
: PLA
|
||||
TYA
|
||||
AND #$F8 ; MASK OFF SLOT #
|
||||
CMP #IOCTL_OPEN
|
||||
BNE :+
|
||||
LDA #<THREAD_YIELD ; REMOVE SOFTWARE TIMER
|
||||
STA LINK_YIELD
|
||||
LDA #>THREAD_YIELD
|
||||
STA LINK_YIELD+1
|
||||
LDA #$0F ; TURN MOUSE INTS ON
|
||||
BNE SETMOUSE
|
||||
: CMP #IOCTL_CLOSE
|
||||
BNE :+
|
||||
LDA #$08 ; TURN MOUSE OFF
|
||||
BNE SETMOUSE
|
||||
: CMP #IOCTL_DEACTIVATE
|
||||
BNE :+
|
||||
LDA #MOUSECTL_NOIRQ
|
||||
: CMP #MOUSECTL_NOIRQ ; UNINSTALL IRQ HANDLER
|
||||
BNE :+
|
||||
SEI
|
||||
LDA #<SW_TIMER ; RE-INSTALL SW TIMER
|
||||
STA LINK_YIELD
|
||||
LDA #>SW_TIMER
|
||||
STA LINK_YIELD+1
|
||||
BNE SETMOUSE
|
||||
: CMP #IOCTL_ID
|
||||
BEQ :+
|
||||
SEC
|
||||
RTS
|
||||
: LDA #$20 ; MOUSE ID
|
||||
CLC
|
||||
RTS
|
||||
;
|
||||
; VBLANK TIMER AND MOUSE IRQ
|
||||
;
|
||||
MOUSE_IRQ: STA TMP
|
||||
SERVEMOUSE: JSR $C400
|
||||
BCS VBLEXIT ; NOT MOUSE INT
|
||||
LDY TMP ; CHECK MOUSE INT CAUSE
|
||||
LDA $0778,Y
|
||||
PHA
|
||||
AND #$08 ; WAS IT VLB?
|
||||
BEQ MOUSEEXIT ; NOPE, MOVE OR BUTTON
|
||||
VBLTIC: LDX #$00
|
||||
LDA #$11 ; 17 MSEC (2/3 OF THE TIME)
|
||||
DEC TIMERADJUST
|
||||
BNE :+
|
||||
LDA #$02
|
||||
STA TIMERADJUST
|
||||
LDA #$10 ; 16 MSEC (1/3 OF THE TIME)
|
||||
: JSR SYSTEM_TIC
|
||||
MOUSEEXIT: PLA
|
||||
AND #$86 ; MOUSE MOVE OR BUTTON ACTIVE
|
||||
BEQ VBLEXIT
|
||||
XREGMOUSE1: LDX #$C4
|
||||
YREGMOUSE1: LDY #$40
|
||||
READMOUSE: JSR $C400 ; IIGS REQUIRES THIS HAPPEN IN IRQ
|
||||
CLC
|
||||
RTS
|
||||
VBLEXIT: SEC
|
||||
RTS
|
||||
MOUSE_DRVR_END EQU *
|
||||
|
||||
package apple2;
|
||||
/*
|
||||
* This class interfaces directly with the mouse device driver.
|
||||
*/
|
||||
public class Mouse
|
||||
{
|
||||
static private int slot, mouseSlot, mouseCtrl, ctrlRead, addrXPos, addrYPos;
|
||||
static public int xPos, yPos, status;
|
||||
|
||||
public static boolean enable()
|
||||
{
|
||||
//
|
||||
// Search for mouse card and disable VBL interrupts
|
||||
//
|
||||
for (slot = 1; slot < 8; slot++)
|
||||
{
|
||||
int mouse = vm02.call((1 << 19), 0x90 + (slot << 1)); // ID device
|
||||
if ((mouse & 0x010000FF) == 0x20) // CARRY clear == valid device IOCTL, 0x20 == mouse card ID
|
||||
{
|
||||
mouseCtrl = 0x90 + (slot << 1);
|
||||
mouseSlot = slot << 16;
|
||||
ctrlRead = mouseSlot | 0x801400;
|
||||
addrXPos = vm02.peekWord(0x0370 + (slot << 1)) + 2;
|
||||
addrYPos = addrXPos + 2;
|
||||
return (vm02.call(mouseSlot | (3 << 19), mouseCtrl) & 0x01000000) == 0; // open port
|
||||
}
|
||||
}
|
||||
slot = 0;
|
||||
return false;
|
||||
}
|
||||
public static void disable()
|
||||
{
|
||||
vm02.call(mouseSlot | (4<<19), mouseCtrl); // close port
|
||||
}
|
||||
public static void disableIRQ()
|
||||
{
|
||||
int vblSlot, vbl;
|
||||
//
|
||||
// Search for mouse card and disable/remove interrupts
|
||||
//
|
||||
for (vblSlot = 1; vblSlot < 8; vblSlot++)
|
||||
{
|
||||
vbl = vm02.call((1 << 19), 0x90 + (vblSlot << 1)); // ID device
|
||||
if ((vbl & 0x010000FF) == 0x20) // CARRY clear == valid device IOCTL, 0x20 == mouse card ID
|
||||
{
|
||||
vm02.call((vblSlot << 16) | (17 << 19), 0x90 + (vblSlot << 1)); // MOUSECTL_UNVBL
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
public static int slotMask()
|
||||
{
|
||||
return (1 << slot);
|
||||
}
|
||||
public static void update()
|
||||
{
|
||||
status = vm02.call(ctrlRead, mouseCtrl) & 0xFF; // CALL_FW ReadMouse
|
||||
xPos = vm02.peekWord(addrXPos);
|
||||
yPos = vm02.peekWord(addrYPos);
|
||||
}
|
||||
}
|
||||
@@ -500,7 +500,7 @@ def etherServiceIP
|
||||
lclport = swab(rxptr=>udp_dst)
|
||||
for i = 1 to MAX_UDP_NOTIFIES
|
||||
if port=>notify_port == lclport
|
||||
port=>notify_func(@iphdr=>ip_src,swab(rxptr=>udp_src),rxptr+t_udphdr,swab(rxptr=>udp_len),port=>notify_parm)
|
||||
port=>notify_func(@iphdr=>ip_src,swab(rxptr=>udp_src),rxptr+t_udphdr,swab(rxptr=>udp_len)-t_udphdr,port=>notify_parm)
|
||||
break
|
||||
fin
|
||||
port = port + t_notify
|
||||
|
||||
12
src/makefile
12
src/makefile
@@ -30,12 +30,14 @@ SNDSEQ = rel/apple/SNDSEQ\#FE1000
|
||||
PLAYSEQ = rel/apple/PLAYSEQ\#FE1000
|
||||
SANITY = rel/SANITY\#FE1000
|
||||
RPNCALC = rel/RPNCALC\#FE1000
|
||||
MOUSE = rel/apple/MOUSE\#FE1000
|
||||
UTHERNET2 = rel/apple/UTHERNET2\#FE1000
|
||||
UTHERNET = rel/apple/UTHERNET\#FE1000
|
||||
ETHERIP = rel/ETHERIP\#FE1000
|
||||
INET = rel/INET\#FE1000
|
||||
DHCP = rel/DHCP\#FE1000
|
||||
HTTPD = rel/HTTPD\#FE1000
|
||||
TFTPD = rel/TFTPD\#FE1000
|
||||
DGR = rel/apple/DGR\#FE1000
|
||||
GRAFIX = rel/apple/GRAFIX\#FE1000
|
||||
GFXDEMO = rel/apple/GFXDEMO\#FE1000
|
||||
@@ -75,7 +77,7 @@ TXTTYPE = .TXT
|
||||
#SYSTYPE = \#FF2000
|
||||
#TXTTYPE = \#040000
|
||||
|
||||
apple: $(PLVMZP_APL) $(PLASM) $(PLVM) $(PLVM01) $(PLVM02) $(PLVM802) $(PLVM03) $(CMD) $(PLASMAPLASM) $(CODEOPT) $(ARGS) $(MEMMGR) $(MEMTEST) $(FIBER) $(FIBERTEST) $(LONGJMP) $(ED) $(MON) $(SOS) $(ROD) $(SIEVE) $(UTHERNET2) $(UTHERNET) $(ETHERIP) $(INET) $(DHCP) $(HTTPD) $(ROGUE) $(ROGUEMAP) $(ROGUECOMBAT) $(GRAFIX) $(GFXDEMO) $(DGR) $(DGRTEST) $(FILEIO_APL) $(CONIO_APL) $(JOYBUZZ) $(PORTIO) $(SPIPORT) $(SDFAT) $(FATCAT) $(FATGET) $(FATPUT) $(FATWDSK) $(FATRDSK) $(SANE) $(FPSTR) $(FPU) $(SANITY) $(RPNCALC) $(SNDSEQ) $(PLAYSEQ)
|
||||
apple: $(PLVMZP_APL) $(PLASM) $(PLVM) $(PLVM01) $(PLVM02) $(PLVM802) $(PLVM03) $(CMD) $(PLASMAPLASM) $(CODEOPT) $(ARGS) $(MEMMGR) $(MEMTEST) $(FIBER) $(FIBERTEST) $(LONGJMP) $(ED) $(MON) $(SOS) $(ROD) $(SIEVE) $(MOUSE) $(UTHERNET2) $(UTHERNET) $(ETHERIP) $(INET) $(DHCP) $(HTTPD) $(TFTPD) $(ROGUE) $(ROGUEMAP) $(ROGUECOMBAT) $(GRAFIX) $(GFXDEMO) $(DGR) $(DGRTEST) $(FILEIO_APL) $(CONIO_APL) $(JOYBUZZ) $(PORTIO) $(SPIPORT) $(SDFAT) $(FATCAT) $(FATGET) $(FATPUT) $(FATWDSK) $(FATRDSK) $(SANE) $(FPSTR) $(FPU) $(SANITY) $(RPNCALC) $(SNDSEQ) $(PLAYSEQ)
|
||||
-rm vmsrc/plvmzp.inc
|
||||
|
||||
c64: $(PLVMZP_C64) $(PLASM) $(PLVM) $(PLVMC64)
|
||||
@@ -260,6 +262,14 @@ $(HTTPD): samplesrc/httpd.pla $(PLVM02) $(PLASM)
|
||||
./$(PLASM) -AMOW < samplesrc/httpd.pla > samplesrc/httpd.a
|
||||
acme --setpc 4094 -o $(HTTPD) samplesrc/httpd.a
|
||||
|
||||
$(TFTPD): samplesrc/tftpd.pla $(PLVM02) $(PLASM)
|
||||
./$(PLASM) -AMOW < samplesrc/tftpd.pla > samplesrc/tftpd.a
|
||||
acme --setpc 4094 -o $(TFTPD) samplesrc/tftpd.a
|
||||
|
||||
$(MOUSE): libsrc/apple/mouse.pla $(PLVM02) $(PLASM)
|
||||
./$(PLASM) -AMOW < libsrc/apple/mouse.pla > libsrc/apple/mouse.a
|
||||
acme --setpc 4094 -o $(MOUSE) libsrc/apple/mouse.a
|
||||
|
||||
$(UTHERNET): libsrc/apple/uthernet.pla $(PLVM02) $(PLASM)
|
||||
./$(PLASM) -AMOW < libsrc/apple/uthernet.pla > libsrc/apple/uthernet.a
|
||||
acme --setpc 4094 -o $(UTHERNET) libsrc/apple/uthernet.a
|
||||
|
||||
@@ -25,6 +25,7 @@ cp rel/SANE#FE1000 prodos/sys/SANE.REL
|
||||
cp rel/apple/SDFAT#FE1000 prodos/sys/SDFAT.REL
|
||||
cp rel/apple/SPIPORT#FE1000 prodos/sys/SPIPORT.REL
|
||||
cp rel/apple/SNDSEQ#FE1000 prodos/sys/SNDSEQ.REL
|
||||
cp rel/apple/MOUSE#FE1000 prodos/sys/MOUSE.REL
|
||||
cp rel/apple/UTHERNET#FE1000 prodos/sys/UTHERNET.REL
|
||||
cp rel/apple/UTHERNET2#FE1000 prodos/sys/UTHERNET2.REL
|
||||
cp rel/apple/SOS#FE1000 prodos/sys/SOS.REL
|
||||
@@ -59,6 +60,7 @@ cp samplesrc/APPLE3.PIX#060000 prodos/demos/apple3/APPLE3.PIX.BIN
|
||||
mkdir prodos/demos/net
|
||||
cp rel/HTTPD#FE1000 prodos/demos/net/HTTPD.REL
|
||||
cp samplesrc/index.html prodos/demos/net/INDEX.HTML.TXT
|
||||
cp rel/TFTPD#FE1000 prodos/sys/TFTPD.REL
|
||||
|
||||
mkdir prodos/demos/music
|
||||
cp rel/apple/PLAYSEQ#FE1000 prodos/demos/music/PLAYSEQ.REL
|
||||
@@ -87,6 +89,7 @@ cp samplesrc/rogue.pla prodos/bld/ROGUE.PLA.TXT
|
||||
cp samplesrc/rogue.map.pla prodos/bld/ROGUE.MAP.PLA.TXT
|
||||
cp samplesrc/rogue.combat.pla prodos/bld/ROGUE.COMBAT.PLA.TXT
|
||||
cp samplesrc/gfxdemo.pla prodos/bld/GFXDEMO.PLA.TXT
|
||||
cp samplesrc/mousetest.pla prodos/bld/MOUSETEST.PLA.TXT
|
||||
|
||||
mkdir prodos/bld/inc
|
||||
cp inc/args.plh prodos/bld/inc/ARGS.PLH.TXT
|
||||
@@ -108,4 +111,5 @@ cp inc/sndseq.plh prodos/bld/inc/SNDSEQ.PLH.TXT
|
||||
cp inc/spiport.plh prodos/bld/inc/SPIPORT.PLH.TXT
|
||||
cp inc/testlib.plh prodos/bld/inc/TESTLIB.PLH.TXT
|
||||
cp inc/grafix.plh prodos/bld/inc/GRAFIX.PLH.TXT
|
||||
cp inc/mouse.plh prodos/bld/inc/MOUSE.PLH.TXT
|
||||
cp vmsrc/apple/plvmzp.inc prodos/bld/inc/PLVMZP.INC.TXT
|
||||
|
||||
22
src/samplesrc/mousetest.pla
Normal file
22
src/samplesrc/mousetest.pla
Normal file
@@ -0,0 +1,22 @@
|
||||
include "inc/cmdsys.plh"
|
||||
include "inc/conio.plh"
|
||||
include "inc/mouse.plh"
|
||||
|
||||
var count
|
||||
var xPos, yPos, bttn
|
||||
|
||||
Mouse:clampMouse(0, 39, 0, 23)
|
||||
Mouse:setMouse(VBL_INT_ENABLE|MOVE_INT_ENABLE|BUTTON_INT_ENABLE|MOUSE_ENABLE)
|
||||
while ^$C000 < 128
|
||||
if Mouse:chkMouse()
|
||||
conio:gotoxy(xPos, yPos); putc(' ')
|
||||
xPos, yPos, bttn = Mouse:readMouse()#3
|
||||
conio:gotoxy(xPos, yPos); putc(bttn & BUTTON_DOWN ?? '+' :: '^')
|
||||
fin
|
||||
if Mouse:chkVBL()
|
||||
^$400++
|
||||
fin
|
||||
loop
|
||||
getc
|
||||
Mouse:detachMouse()
|
||||
done
|
||||
@@ -260,8 +260,8 @@ end
|
||||
//
|
||||
|
||||
export def drawmap(xorg, yorg, viewfield, viewdir, lightdist, viewdist)
|
||||
byte o, l, dist, tile, adjtile, occluded, darkness
|
||||
word ymap, xmap, imap
|
||||
byte l, dist, tile, adjtile, occluded, darkness
|
||||
word ymap, xmap, imap, o
|
||||
byte yscr, xscr
|
||||
|
||||
if viewdist > beamdepth
|
||||
|
||||
503
src/samplesrc/tftpd.pla
Normal file
503
src/samplesrc/tftpd.pla
Normal file
@@ -0,0 +1,503 @@
|
||||
//
|
||||
// TFTP Daemon
|
||||
//
|
||||
include "inc/cmdsys.plh"
|
||||
include "inc/inet.plh"
|
||||
include "inc/fileio.plh"
|
||||
include "inc/conio.plh"
|
||||
//
|
||||
// TFTP values
|
||||
//
|
||||
const TFTP_PORT = 69
|
||||
const TID_INC = $0010
|
||||
const RRQ = $0100
|
||||
const WRQ = $0200
|
||||
const DATAPKT = $0300
|
||||
const ACKPKT = $0400
|
||||
const ERRPKT = $0500
|
||||
struc t_errPkt
|
||||
word errOp
|
||||
word errCode
|
||||
byte errStr[]
|
||||
byte errStrNull
|
||||
end
|
||||
struc t_ackPkt
|
||||
word ackOp
|
||||
word ackBlock
|
||||
end
|
||||
struc t_datPkt
|
||||
word datOp
|
||||
word datBlock
|
||||
byte datBytes[]
|
||||
end
|
||||
res[t_errPkt] tftpError = $00, $05, $00, $00, $00
|
||||
res[t_ackPkt] tftpAck = $00, $04, $00, $00
|
||||
//
|
||||
// Current file operations
|
||||
//
|
||||
byte ref, type, , netscii, filename[256]
|
||||
word aux, block
|
||||
word buff, TID = $1001
|
||||
word portTFTP, portTID
|
||||
//
|
||||
// Swap bytes in word
|
||||
//
|
||||
asm swab(val)
|
||||
!SOURCE "vmsrc/plvmzp.inc"
|
||||
LDA ESTKL,X
|
||||
LDY ESTKH,X
|
||||
STA ESTKH,X
|
||||
STY ESTKL,X
|
||||
RTS
|
||||
end
|
||||
//
|
||||
// Translate 'in' value to 'out' value
|
||||
//
|
||||
asm xlat(in, out, buf, len)#0
|
||||
INX
|
||||
INX
|
||||
INX
|
||||
INX
|
||||
LDA ESTKL-4,X
|
||||
ORA ESTKH-4,X
|
||||
BEQ XLATEX
|
||||
LDA ESTKL-3,X
|
||||
STA SRCL
|
||||
LDA ESTKH-3,X
|
||||
STA SRCH
|
||||
LDA ESTKL-1,X
|
||||
LDY ESTKL-4,X
|
||||
BEQ XLATLP
|
||||
INC ESTKH-4,X
|
||||
LDY #$00
|
||||
XLATLP CMP (SRC),Y
|
||||
BNE +
|
||||
LDA ESTKL-2,X
|
||||
STA (SRC),Y
|
||||
LDA ESTKL-1,X
|
||||
+ INY
|
||||
BNE +
|
||||
INC DSTH
|
||||
INC SRCH
|
||||
+ DEC ESTKL-4,X
|
||||
BNE XLATLP
|
||||
DEC ESTKH-4,X
|
||||
BNE XLATLP
|
||||
XLATEX RTS
|
||||
end
|
||||
//
|
||||
// Convert byte to two hex chars
|
||||
//
|
||||
def btoh(cptr, b)#0
|
||||
byte h
|
||||
|
||||
h = ((b >> 4) & $0F) + '0'
|
||||
if h > '9'
|
||||
h = h + 7
|
||||
fin
|
||||
^cptr = h
|
||||
cptr++
|
||||
h = (b & $0F) + '0'
|
||||
if h > '9'
|
||||
h = h + 7
|
||||
fin
|
||||
^cptr = h
|
||||
end
|
||||
|
||||
def hexByte(hexChars)
|
||||
byte lo, hi
|
||||
|
||||
lo = toupper(^(hexChars + 1)) - '0'
|
||||
if lo > 9
|
||||
lo = lo - 7
|
||||
fin
|
||||
hi = toupper(^hexChars) - '0'
|
||||
if hi > 9
|
||||
hi = hi - 7
|
||||
fin
|
||||
return (hi << 4) | lo
|
||||
end
|
||||
def hexWord(hexChars)
|
||||
return (hexByte(hexChars) << 8) | hexByte(hexChars + 2)
|
||||
end
|
||||
def mkProName(netName, proName)#3
|
||||
byte n, l, ascii, proType
|
||||
word proAux
|
||||
|
||||
proType = $02 // default to BIN
|
||||
proAux = $0000 // default to 0
|
||||
//
|
||||
// Check for CiderPress style extension
|
||||
//
|
||||
for l = 0 to 255
|
||||
if netName->[l] == 0; break; fin
|
||||
next
|
||||
ascii = toupper(netName->[l + 1]) == 'N' // Netscii mode
|
||||
if l > 7 and ^(netName + l - 7) == '#'
|
||||
proType = hexByte(netName + l - 6)
|
||||
proAux = hexWord(netName + l - 4)
|
||||
l = l - 7
|
||||
fin
|
||||
memcpy(proName + 1, netName, l)
|
||||
^proName = l
|
||||
return ascii, proType, proAux
|
||||
end
|
||||
def mkNetName(proName, netName)
|
||||
word l, n
|
||||
byte fileinfo[t_fileinfo]
|
||||
|
||||
if !fileio:getfileinfo(proName, @fileinfo)
|
||||
//
|
||||
// Scan backward looking for dir seperator
|
||||
//
|
||||
l = ^proName
|
||||
for n = l downto 1
|
||||
if ^(proName + n) == '/'
|
||||
break
|
||||
fin
|
||||
next
|
||||
memcpy(netName + 1, proName + 1 + n, l - n)
|
||||
^netName = l - n + 7
|
||||
//
|
||||
// Build CiderPress style extension
|
||||
//
|
||||
n = netName + ^netName - 6
|
||||
^n = '#'
|
||||
btoh(n + 1, fileinfo.file_type)
|
||||
btoh(n + 3, fileinfo.aux_type.1)
|
||||
btoh(n + 5, fileinfo.aux_type)
|
||||
else
|
||||
//
|
||||
// Error getting info on file
|
||||
//
|
||||
puts("Error reading "); puts(proName); putln
|
||||
return -1
|
||||
fin
|
||||
return 0
|
||||
end
|
||||
|
||||
def readUDP(ipsrc, portsrc, data, len, param)
|
||||
word err
|
||||
|
||||
err = 0
|
||||
when *data
|
||||
is $0500 // Error
|
||||
err = *data
|
||||
is $0400 // Ack
|
||||
if swab(data=>ackBlock) <> block
|
||||
puts("RRQ: Out-of-sequence block\n")
|
||||
err = $0800 // Out-of-sequence block
|
||||
break
|
||||
fin
|
||||
if param == 512 // Size of initial read
|
||||
param = fileio:read(ref, buff+datBytes, 512)
|
||||
if type == $04 // TXT type
|
||||
xlat($0D, $0A, buff+datBytes, param)
|
||||
fin
|
||||
block++
|
||||
buff=>datBlock = swab(block)
|
||||
iNet:sendUDP(portTID, ipsrc, portsrc, buff, t_datPkt + param)
|
||||
fin
|
||||
if err
|
||||
tftpError:errCode = err
|
||||
iNet:sendUDP(portTID, ipsrc, portsrc, @tftpError, t_errPkt)
|
||||
fin
|
||||
if param < 512 or err
|
||||
//
|
||||
// All done
|
||||
//
|
||||
iNet:closeUDP(portTID)
|
||||
fileio:close(ref)
|
||||
ref = 0
|
||||
fin
|
||||
break
|
||||
otherwise
|
||||
puts("TFTP: RRQ Unexpected packet opcode: $"); puth(*data); putln
|
||||
wend
|
||||
return 0
|
||||
end
|
||||
def writeUDP(ipsrc, portsrc, data, len, param)
|
||||
word err
|
||||
|
||||
err = 0
|
||||
when *data
|
||||
is $0300 // Data packet
|
||||
if swab(data=>datBlock) <> block
|
||||
puts("WRQ: Out-of-sequence block\n")
|
||||
err = $0800 // Out-of-sequence block
|
||||
break
|
||||
fin
|
||||
len = len - t_datPkt
|
||||
if type == $04 // TXT type
|
||||
xlat($0A, $0D, data+datBytes, len)
|
||||
fin
|
||||
if fileio:write(ref, data+datBytes, len) <> len
|
||||
puts("WRQ: File write error\n")
|
||||
tftpError:errCode = $0300 // Disk full error
|
||||
break
|
||||
fin
|
||||
if not err
|
||||
tftpAck:ackBlock = swab(block)
|
||||
block++
|
||||
iNet:sendUDP(portTID, ipsrc, portsrc, @tftpAck, t_ackPkt)
|
||||
else
|
||||
tftpError:errCode = err
|
||||
iNet:sendUDP(portTID, ipsrc, portsrc, @tftpError, t_errPkt)
|
||||
fin
|
||||
if len < 512 or err
|
||||
//
|
||||
// All done
|
||||
//
|
||||
iNet:closeUDP(portTID)
|
||||
fileio:close(ref)
|
||||
ref = 0
|
||||
fin
|
||||
break
|
||||
otherwise
|
||||
puts("WRQ: Unexpected packet opcode: $"); puth(*data); putln
|
||||
wend
|
||||
return 0
|
||||
end
|
||||
def servUDP(ipsrc, portsrc, data, len, param)
|
||||
byte info[24]
|
||||
|
||||
when *data
|
||||
is RRQ // Read request
|
||||
//
|
||||
// Initiate file read
|
||||
//
|
||||
if ref
|
||||
//
|
||||
// File already open and active
|
||||
//
|
||||
tftpError:errCode = $0300 // Allocation exceeded
|
||||
iNet:sendUDP(portTFTP, ipsrc, portsrc, @tftpError, t_errPkt)
|
||||
return 0
|
||||
fin
|
||||
//
|
||||
// Extract filename
|
||||
//
|
||||
netscii, type, aux = mkProName(data + 2, @filename)
|
||||
ref = fileio:open(@filename)
|
||||
if not ref
|
||||
puts("Error opening file: "); puts(@filename)
|
||||
puts(", Error: "); putb(perr); putln
|
||||
tftpError:errCode = $0100 // File not found
|
||||
iNet:sendUDP(portTFTP, ipsrc, portsrc, @tftpError, t_errPkt)
|
||||
return 0
|
||||
fin
|
||||
info.0 = $0A
|
||||
info:1 = @filename
|
||||
syscall($C4, @info)
|
||||
type = info.4
|
||||
puts("Reading file: "); puts(@filename); putln
|
||||
TID = (TID + TID_INC) | $1000
|
||||
block = 1
|
||||
buff=>datBlock = swab(block)
|
||||
len = fileio:read(ref, buff+datBytes, 512)
|
||||
if type == $04 // TXT type
|
||||
xlat($0D, $0A, buff+datBytes, 512)
|
||||
fin
|
||||
portTID = iNet:openUDP(TID, @readUDP, len)
|
||||
iNet:sendUDP(portTID, ipsrc, portsrc, buff, t_datPkt + len)
|
||||
break
|
||||
is WRQ // Write request
|
||||
//
|
||||
// Initiate file write
|
||||
//
|
||||
if ref
|
||||
//
|
||||
// File already open and active
|
||||
//
|
||||
tftpError:errCode = $0300 // Allocation exceeded
|
||||
iNet:sendUDP(portTFTP, ipsrc, portsrc, @tftpError, t_errPkt)
|
||||
return 0
|
||||
fin
|
||||
//
|
||||
// Extract filename
|
||||
//
|
||||
netscii, type, aux = mkProName(data + 2, @filename)
|
||||
fileio:destroy(@filename)
|
||||
if fileio:create(@filename, type, aux)
|
||||
puts("Create file error: "); putb(perr); putln
|
||||
fin
|
||||
ref = fileio:open(@filename)
|
||||
if not ref
|
||||
puts("Error opening file: "); puts(@filename)
|
||||
puts(", Error: "); putb(perr); putln
|
||||
tftpError:errCode = $0200 // Access violation
|
||||
iNet:sendUDP(portTFTP, ipsrc, portsrc, @tftpError, t_errPkt)
|
||||
return 0
|
||||
fin
|
||||
puts("Writing file: "); puts(@filename); putln
|
||||
TID = (TID + TID_INC) | $1000
|
||||
block = 1
|
||||
tftpAck:ackBlock = 0
|
||||
portTID = iNet:openUDP(TID, @writeUDP, 0)
|
||||
iNet:sendUDP(portTID, ipsrc, portsrc, @tftpAck, t_ackPkt)
|
||||
break
|
||||
otherwise
|
||||
puts("TFTP: Server Unexpected packet opcode: $"); puth(*data); putln
|
||||
wend
|
||||
return 0
|
||||
end
|
||||
|
||||
if !iNet:initIP()
|
||||
return -1
|
||||
fin
|
||||
puts("TFTP Server Version 0.1\n")
|
||||
portTFTP = iNet:openUDP(TFTP_PORT, @servUDP, 0)
|
||||
//
|
||||
// Alloc aligned file/io buffers
|
||||
//
|
||||
buff = heapalloc(t_datPkt + 512)
|
||||
buff=>datOp = $0300 // Data op
|
||||
//
|
||||
// Service IP
|
||||
//
|
||||
repeat
|
||||
iNet:serviceIP()
|
||||
until conio:keypressed()
|
||||
done
|
||||
|
||||
Experpts from: RFC 1350, TFTP Revision 2, July 1992
|
||||
|
||||
TFTP Formats
|
||||
|
||||
Type Op # Format without header
|
||||
|
||||
2 bytes string 1 byte string 1 byte
|
||||
-----------------------------------------------
|
||||
RRQ/ | 01/02 | Filename | 0 | Mode | 0 |
|
||||
WRQ -----------------------------------------------
|
||||
2 bytes 2 bytes n bytes
|
||||
---------------------------------
|
||||
DATA | 03 | Block # | Data |
|
||||
---------------------------------
|
||||
2 bytes 2 bytes
|
||||
-------------------
|
||||
ACK | 04 | Block # |
|
||||
--------------------
|
||||
2 bytes 2 bytes string 1 byte
|
||||
----------------------------------------
|
||||
ERROR | 05 | ErrorCode | ErrMsg | 0 |
|
||||
----------------------------------------
|
||||
|
||||
Initial Connection Protocol for reading a file
|
||||
|
||||
1. Host A sends a "RRQ" to host B with source= A's TID,
|
||||
destination= 69.
|
||||
|
||||
2. Host B sends a "DATA" (with block number= 1) to host A with
|
||||
source= B's TID, destination= A's TID.
|
||||
|
||||
Error Codes
|
||||
|
||||
Value Meaning
|
||||
|
||||
0 Not defined, see error message (if any).
|
||||
1 File not found.
|
||||
2 Access violation.
|
||||
3 Disk full or allocation exceeded.
|
||||
4 Illegal TFTP operation.
|
||||
5 Unknown transfer ID.
|
||||
6 File already exists.
|
||||
7 No such user.
|
||||
|
||||
Internet User Datagram Header [2]
|
||||
|
||||
(This has been included only for convenience. TFTP need not be
|
||||
implemented on top of the Internet User Datagram Protocol.)
|
||||
|
||||
Format
|
||||
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Source Port | Destination Port |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Length | Checksum |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
|
||||
Values of Fields
|
||||
|
||||
|
||||
Source Port Picked by originator of packet.
|
||||
|
||||
Dest. Port Picked by destination machine (69 for RRQ or WRQ).
|
||||
|
||||
Length Number of bytes in UDP packet, including UDP header.
|
||||
|
||||
Checksum Reference 2 describes rules for computing checksum.
|
||||
(The implementor of this should be sure that the
|
||||
correct algorithm is used here.)
|
||||
Field contains zero if unused.
|
||||
|
||||
Note: TFTP passes transfer identifiers (TID's) to the Internet User
|
||||
Datagram protocol to be used as the source and destination ports.
|
||||
|
||||
|
||||
A transfer is established by sending a request (WRQ to write onto a
|
||||
foreign file system, or RRQ to read from it), and receiving a
|
||||
positive reply, an acknowledgment packet for write, or the first data
|
||||
packet for read. In general an acknowledgment packet will contain
|
||||
the block number of the data packet being acknowledged. Each data
|
||||
packet has associated with it a block number; block numbers are
|
||||
consecutive and begin with one. Since the positive response to a
|
||||
write request is an acknowledgment packet, in this special case the
|
||||
block number will be zero. (Normally, since an acknowledgment packet
|
||||
is acknowledging a data packet, the acknowledgment packet will
|
||||
contain the block number of the data packet being acknowledged.) If
|
||||
the reply is an error packet, then the request has been denied.
|
||||
|
||||
In order to create a connection, each end of the connection chooses a
|
||||
TID for itself, to be used for the duration of that connection. The
|
||||
TID's chosen for a connection should be randomly chosen, so that the
|
||||
probability that the same number is chosen twice in immediate
|
||||
succession is very low. Every packet has associated with it the two
|
||||
TID's of the ends of the connection, the source TID and the
|
||||
destination TID. These TID's are handed to the supporting UDP (or
|
||||
other datagram protocol) as the source and destination ports. A
|
||||
requesting host chooses its source TID as described above, and sends
|
||||
its initial request to the known TID 69 decimal (105 octal) on the
|
||||
serving host. The response to the request, under normal operation,
|
||||
uses a TID chosen by the server as its source TID and the TID chosen
|
||||
for the previous message by the requestor as its destination TID.
|
||||
The two chosen TID's are then used for the remainder of the transfer.
|
||||
|
||||
As an example, the following shows the steps used to establish a
|
||||
connection to write a file. Note that WRQ, ACK, and DATA are the
|
||||
names of the write request, acknowledgment, and data types of packets
|
||||
respectively. The appendix contains a similar example for reading a
|
||||
file.
|
||||
|
||||
1. Host A sends a "WRQ" to host B with source= A's TID,
|
||||
destination= 69.
|
||||
|
||||
2. Host B sends a "ACK" (with block number= 0) to host A with
|
||||
source= B's TID, destination= A's TID.
|
||||
|
||||
At this point the connection has been established and the first data
|
||||
packet can be sent by Host A with a sequence number of 1. In the
|
||||
next step, and in all succeeding steps, the hosts should make sure
|
||||
that the source TID matches the value that was agreed on in steps 1
|
||||
and 2. If a source TID does not match, the packet should be
|
||||
discarded as erroneously sent from somewhere else. An error packet
|
||||
should be sent to the source of the incorrect packet, while not
|
||||
disturbing the transfer. This can be done only if the TFTP in fact
|
||||
receives a packet with an incorrect TID. If the supporting protocols
|
||||
do not allow it, this particular error condition will not arise.
|
||||
|
||||
The following example demonstrates a correct operation of the
|
||||
protocol in which the above situation can occur. Host A sends a
|
||||
request to host B. Somewhere in the network, the request packet is
|
||||
duplicated, and as a result two acknowledgments are returned to host
|
||||
A, with different TID's chosen on host B in response to the two
|
||||
requests. When the first response arrives, host A continues the
|
||||
connection. When the second response to the request arrives, it
|
||||
should be rejected, but there is no reason to terminate the first
|
||||
connection. Therefore, if different TID's are chosen for the two
|
||||
connections on host B and host A checks the source TID's of the
|
||||
messages it receives, the first connection can be maintained while
|
||||
the second is rejected by returning an error packet.
|
||||
@@ -1589,6 +1589,7 @@ int parse_defs(void)
|
||||
next_line();
|
||||
} while (scantoken != END_TOKEN);
|
||||
scan();
|
||||
infunc = 0;
|
||||
return (1);
|
||||
}
|
||||
return (scantoken == EOL_TOKEN);
|
||||
|
||||
@@ -40,7 +40,7 @@ predef sext(a)#1, divmod(a,b)#2, execmod(modfile)#1
|
||||
//
|
||||
// Exported CMDSYS table
|
||||
//
|
||||
word version = $0110 // 01.10
|
||||
word version = $0120 // 01.20
|
||||
word syspath
|
||||
word syscmdln
|
||||
word = @execmod
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
const MACHID = $BF98
|
||||
const iobuffer = $0800
|
||||
const databuff = $2000
|
||||
const RELADDR = $1000
|
||||
const symtbl = $0C00
|
||||
const freemem = $0006
|
||||
@@ -38,7 +37,7 @@ predef execmod(modfile)#1
|
||||
//
|
||||
// Exported CMDSYS table
|
||||
//
|
||||
word version = $0110 // 01.10
|
||||
word version = $0120 // 01.20
|
||||
word syspath
|
||||
word syscmdln
|
||||
word = @execmod
|
||||
@@ -1260,9 +1259,9 @@ def volumes()#0
|
||||
|
||||
params.0 = 2
|
||||
params.1 = 0
|
||||
params:2 = databuff
|
||||
params:2 = heap
|
||||
perr = syscall($C5, @params)
|
||||
strbuf = databuff
|
||||
strbuf = heap
|
||||
for i = 0 to 15
|
||||
^strbuf = ^strbuf & $0F
|
||||
if ^strbuf
|
||||
@@ -1287,12 +1286,12 @@ def catalog(path)#0
|
||||
fin
|
||||
firstblk = 1
|
||||
repeat
|
||||
if read(refnum, databuff, 512) == 512
|
||||
entry = databuff + 4
|
||||
if read(refnum, heap, 512) == 512
|
||||
entry = heap + 4
|
||||
if firstblk
|
||||
entrylen = databuff.$23
|
||||
entriesblk = databuff.$24
|
||||
filecnt = databuff:$25
|
||||
entrylen = heap->$23
|
||||
entriesblk = heap->$24
|
||||
filecnt = heap=>$25
|
||||
entry = entry + entrylen
|
||||
fin
|
||||
for i = firstblk to entriesblk
|
||||
@@ -1372,7 +1371,7 @@ def resetmemfiles()#0
|
||||
//
|
||||
// Close all files
|
||||
//
|
||||
^$BFD8 = 0
|
||||
^$BF94 = 0
|
||||
close(0)
|
||||
//
|
||||
// Set memory bitmap
|
||||
@@ -1390,7 +1389,7 @@ def execsys(sysfile)#0
|
||||
striptrail(sysfile)
|
||||
refnum = open(sysfile)
|
||||
if refnum
|
||||
len = read(refnum, databuff, $FFFF)
|
||||
len = read(refnum, $2000, $FFFF)
|
||||
resetmemfiles()
|
||||
if len
|
||||
strcpy(sysfile, $280)
|
||||
|
||||
@@ -1447,6 +1447,7 @@ ICALX LDA ESTKL,X
|
||||
PHP
|
||||
PLA
|
||||
STA PSR
|
||||
SEI
|
||||
STA ALTRDON
|
||||
PLA
|
||||
STA IPH
|
||||
|
||||
@@ -29,7 +29,7 @@ predef execmod(modfile)#1
|
||||
//
|
||||
// Exported CMDSYS table
|
||||
//
|
||||
word version = $0110 // 01.10
|
||||
word version = $0120 // 01.20
|
||||
word syspath
|
||||
word cmdlnptr
|
||||
word = @execmod
|
||||
|
||||
Reference in New Issue
Block a user