Matchbox sized 6502 / Z80 / 6809 Co Pro
Matchbox sized 6502 / Z80 / 6809 Co Pro
Hi all,
Yesterday I received a small package from a very generous donor (thanks Ed....): It's a GODIL GOP XC3S200 module:
http://www.oho-elektronik.de/pics/UM_XC3S200.pdf
This thing is truly tiny, and is an amazingly neat bit of hardware. It could easily be turned into a complete Atom.
It's soon going to be a 6502 second processor. I just need to make a small PCB to connect the 24 pin DIL socket to a 40 pin IDC socket. The plan is to initially test this on the BBC Model B, and then have a go at connecting it to the Atom.
On Tuesday night I started cutting and pasting VHDL from the Atom FPGA project to make a second processor with just 4 components:
- a DCM (clock thingy)
- the T65 6502 core (4MHz initially)
- a ROM
- Ed/Richards Tube Verilog interface
Here's the VHDL in GitHub:
https://github.com/hoglet67/CoPro6502/b ... ro6502.vhd
There's a small amount of additional logic to implement the boot mode, where code executes initially from ROM, copies itself to RAM, and then on the first tube access starts running from RAM.
Last night I had a go at simulating it, which was a lot of fun, and found several bugs that would have been very hard to debug on real hardware. I've managed to simulate it for about 10ms, which is enough to see it copying itself into RAM, and then disabling boot mode.
At the moment, it's hanging on the first OSWRCH call, because the tube chip isn't initialized, so it's waiting forever to be allowed to send the "Acorn TUBE 6502 64K" message.
In the next post, I'll post JHG's excellent commented disassembly of the 6502 Tube client code, which will serve as a useful reference for the expected shenanigans of the next few days.
I'm going to have a go at trying to get the tube interface properly initialized in the simulation, and see if I can get the code to run any further.
More later....
Dave
Yesterday I received a small package from a very generous donor (thanks Ed....): It's a GODIL GOP XC3S200 module:
http://www.oho-elektronik.de/pics/UM_XC3S200.pdf
This thing is truly tiny, and is an amazingly neat bit of hardware. It could easily be turned into a complete Atom.
It's soon going to be a 6502 second processor. I just need to make a small PCB to connect the 24 pin DIL socket to a 40 pin IDC socket. The plan is to initially test this on the BBC Model B, and then have a go at connecting it to the Atom.
On Tuesday night I started cutting and pasting VHDL from the Atom FPGA project to make a second processor with just 4 components:
- a DCM (clock thingy)
- the T65 6502 core (4MHz initially)
- a ROM
- Ed/Richards Tube Verilog interface
Here's the VHDL in GitHub:
https://github.com/hoglet67/CoPro6502/b ... ro6502.vhd
There's a small amount of additional logic to implement the boot mode, where code executes initially from ROM, copies itself to RAM, and then on the first tube access starts running from RAM.
Last night I had a go at simulating it, which was a lot of fun, and found several bugs that would have been very hard to debug on real hardware. I've managed to simulate it for about 10ms, which is enough to see it copying itself into RAM, and then disabling boot mode.
At the moment, it's hanging on the first OSWRCH call, because the tube chip isn't initialized, so it's waiting forever to be allowed to send the "Acorn TUBE 6502 64K" message.
In the next post, I'll post JHG's excellent commented disassembly of the 6502 Tube client code, which will serve as a useful reference for the expected shenanigans of the next few days.
I'm going to have a go at trying to get the tube interface properly initialized in the simulation, and see if I can get the code to run any further.
More later....
Dave
Last edited by hoglet on Fri Nov 07, 2014 4:18 pm, edited 4 times in total.
Re: Matchbox sized 6502 Co Processor
Commented 6502 Tube Client Code thanks to JGH:
http://mdfs.net/Software/Tube/6502/
The whole thing is only 2KB.
This needs to run from RAM, as the NMI vector at FFFA/FFFB is dynamice updated (by the code at FD65). There is also another piece of self-modifying code at F860).
http://mdfs.net/Software/Tube/6502/
The whole thing is only 2KB.
This needs to run from RAM, as the NMI vector at FFFA/FFFB is dynamice updated (by the code at FD65). There is also another piece of self-modifying code at F860).
Code: Select all
10 REM >Client/src
20 REM Source for 6502 Tube Client
30 REM As supplied with External 6502 Second Processor
40 REM Code copyright Acorn Computer
50 REM Commentary copyright J.G.Harston
60 :
70 IF PAGE>&8000:LOADATN "OS_GetEnv"TOA$:IFLEFT$(A$,5)<>"B6502":OSCLI"B6502"+MID$(A$,INSTR(A$," "))
80 :
90 load%=&F800:DIM mcode% &900
100 :
110 USERV=&200: BRKV=&202:IRQ1V=&204:IRQ2V=&206
120 CLIV=&208:BYTEV=&20A:WORDV=&20C:WRCHV=&20E
130 RDCHV=&210:FILEV=&212:ARGSV=&214:BGetV=&216
140 BPutV=&218:GBPBV=&21A:FINDV=&21C: FSCV=&21E
150 EVNTV=&220: UPTV=&222: NETV=&224: VduV=&226
160 KEYV=&228: INSV=&22A: RemV=&22C: CNPV=&22E
170 IND1V=&230:IND2V=&232:IND3V=&234
180 :
190 ERRBUF=&236:INPBUF=&236
200 :
210 :
220 REM Memory addresses:
230 REM &EE/F = PROG - Current program
240 REM &F0/1 = NUM - hex accumulator
250 REM &F2/3 = MEMTOP - top of memory
260 REM &F4/5 = address of byte transfer address, NMIAddr or ADDR
270 REM &F6/7 = ADDR - Data transfer address
280 REM &F8/9 = String pointer, OSWORD control block
290 REM &FA/B = CTRL - OSFILE, OSGBPB control block, PrText string pointer
300 REM &FC = IRQ A store
310 REM &FD/E => last error
320 REM &FF = Escape flag
330 :
340 FOR P=0TO1
350 P%=load%:O%=mcode%
360 [OPT P*3+4
370 .RESET
380 LDX #&00
390 .LF802
400 LDA &FF00,X:STA &FF00,X :\ Copy entry block to RAM
410 DEX:BNE LF802
420 LDX #&36
430 .LF80D
440 LDA LFF80,X:STA USERV,X :\ Set up default vectors
450 DEX:BPL LF80D
460 TXS:LDX #&F0 :\ Clear stack
470 .LF819
480 LDA &FDFF,X:STA &FDFF,X :\ Copy &FE00-&FEEF to RAM, avoiding
490 DEX:BNE LF819 :\ Tube registers at &FEFx
500 LDY #RESET AND 255:STY &F8 :\ Point to start of ROM
510 LDA #RESET DIV 256:STA &F9
520 .LF82A :\ Copy rest of ROM to RAM
530 LDA (&F8),Y:STA (&F8),Y :\ Copy a page to RAM
540 INY:BNE LF82A :\ Loop for 256 bytes
550 INC &F9:LDA &F9 :\ Inc. address high byte
560 CMP #&FE:BNE LF82A :\ Loop from &F800 to &FDFF
570 LDX #&10
580 .LF83B
590 LDA LF859,X:STA &0100,X :\ Copy jump code to &100
600 DEX:BPL LF83B
610 LDA &EE:STA &F6 :\ Copy &EE/F to &F6/7
620 LDA &EF:STA &F7
630 LDA #&00:STA &FF :\ Clear Escape flag
640 STA &F2:LDA #&F8:STA &F3 :\ Set memtop to start of ROM at &F800
650 JMP &0100 :\ Jump via low memory to page ROM out
660
670 \ Executed in low memory to page ROM out
680 \ --------------------------------------
690 .LF859
700 LDA TubeS1:CLI :\ Check Tube R1 status to page ROM out
710 .LF85D
720 JMP LF860 :\ Jump to initilise I/O with banner
730
740 .LF860
750 JSR PrText :\ Display startup banner
760 EQUB 10:EQUS "Acorn TUBE 6502 64K"
770 EQUB 10:EQUB 10:EQUB 13:EQUB 0
780 NOP
790 LDA #CmdOSLoop AND 255 :\ Next time RESET is soft entered,
800 STA LF85D+1 :\ banner not printed
810 LDA #CmdOSLoop DIV 256
820 STA LF85D+2
830 JSR WaitByte :\ Wait for Acknowledge
840 CMP #&80:BEQ EnterCode :\ If &80, jump to enter code
850 :\ Otherwise, enter command prompt loop
860
870 \ Minimal Command prompt
880 \ ======================
890 .CmdOSLoop
900 LDA #ASC"*":JSR OSWRCH :\ Print '*' prompt
910 LDX #LF95D AND 255
920 LDY #LF95D DIV 256
930 LDA #&00:JSR OSWORD :\ Read line to INPBUF
940 BCS CmdOSEscape
950 LDX #INPBUF AND 255
960 LDY #INPBUF DIV 256 :\ Execute command
970 JSR OS_CLI:JMP CmdOSLoop :\ and loop back for another
980 .CmdOSEscape
990 LDA #&7E:JSR OSBYTE :\ Acknowledge Escape state
1000 BRK:EQUB 17:EQUS "Escape":BRK
1010
1020
1030 \ Enter Code pointer to by &F6/7
1040 \ ==============================
1050 \ Checks to see if code has a ROM header, and verifies
1060 \ it if it has
1070 .EnterCode
1080 LDA &F6:STA &EE:STA &F2 :\ Set current program and memtop
1090 LDA &F7:STA &EF:STA &F3 :\ to address beng entered
1100 LDY #&07:LDA (&EE),Y :\ Get copyright offset
1110 CLD:CLC:ADC &EE:STA &FD
1120 LDA #&00:ADC &EF:STA &FE :\ &FD/E=>copyright message
1130 \
1140 \ Now check for &00,"(C)"
1150 LDY #&00:LDA (&FD),Y:BNE LF8FA :\ Jump if no initial &00
1160 INY:LDA (&FD),Y:CMP #&28:BNE LF8FA :\ Jump if no '('
1170 INY:LDA (&FD),Y:CMP #&43:BNE LF8FA :\ Jump if no 'C'
1180 INY:LDA (&FD),Y:CMP #&29:BNE LF8FA :\ Jump if no ')'
1190 \
1200 \ &00,"(C)" exists
1210 LDY #&06:LDA (&EE),Y :\ Get ROM type
1220 AND #&4F:CMP #&40:BCC NotLanguage :\ b6=0, not a language
1230 AND #&0D:BNE Not6502Code :\ type<>0 and <>2, not 6502 code
1240 .LF8FA
1250 LDA #&01:JMP (&00F2) :\ Enter code with A=1
1260 \
1270 \ Any existing error handler will probably have been overwritten
1280 \ Set up new error handler before generating an error
1290 .NotLanguage
1300 LDA #ErrorHandler AND 255:STA BRKV+0 :\ Claim error handler
1310 LDA #ErrorHandler DIV 256:STA BRKV+1
1320 BRK:EQUB 0:EQUS "This is not a language":EQUB 0
1330
1340 .Not6502Code
1350 LDA #ErrorHandler AND 255:STA BRKV+0 :\ Claim error handler
1360 LDA #ErrorHandler DIV 256:STA BRKV+1
1370 BRK:EQUB 0:EQUS "I cannot run this code":EQUB 0
1380
1390 .ErrorHandler
1400 LDX #&FF:TXS :\ Clear stack
1410 JSR OSNEWL:LDY #&01
1420 .LF94D
1430 LDA (&FD),Y:BEQ LF957 :\ Print error string
1440 JSR OSWRCH:INY:BNE LF94D
1450 .LF957
1460 JSR OSNEWL:JMP CmdOSLoop :\ Jump to command prompt
1470
1480 \ Control block for command prompt input
1490 \ --------------------------------------
1500 .LF95D
1510 EQUW INPBUF :\ Input text to INPBUF at &236
1520 EQUB &CA :\ Up to &CA characters
1530 EQUB &20:EQUB &FF :\ Min=&20, Max=&FF
1540
1550
1560 \ MOS INTERFACE
1570 \ =============
1580 \
1590 \
1600 \ OSWRCH - Send character to output stream
1610 \ ========================================
1620 \ On entry, A =character
1630 \ On exit, A =preserved
1640 \
1650 \ Tube data character --
1660 \
1670 .osWRCH
1680 BIT TubeS1 :\ Read Tube R1 status
1690 NOP:BVC osWRCH :\ Loop until b6 set
1700 STA TubeR1:RTS :\ Send character to Tube R1
1710
1720
1730 \ OSRDCH - Wait for character from input stream
1740 \ =============================================
1750 \ On exit, A =char, Cy=Escape flag
1760 \
1770 \ Tube data &00 -- Carry Char
1780 \
1790 .osRDCH
1800 LDA #&00:JSR SendCommand :\ Send command &00 - OSRDCH
1810 .WaitCarryChar :\ Wait for Carry and A
1820 JSR WaitByte:ASL A :\ Wait for carry
1830 .WaitByte
1840 BIT TubeS2:BPL WaitByte :\ Loop until Tube R2 has data
1850 LDA TubeR2 :\ Fetch character
1860 .NullReturn
1870 RTS
1880
1890
1900 \ Skip Spaces
1910 \ ===========
1920 .SkipSpaces1
1930 INY
1940 .SkipSpaces
1950 LDA (&F8),Y:CMP #&20:BEQ SkipSpaces1
1960 RTS
1970
1980
1990 \ Scan hex
2000 \ ========
2010 .ScanHex
2020 LDX #&00:STX &F0:STX &F1 :\ Clear hex accumulator
2030 .LF98C
2040 LDA (&F8),Y :\ Get current character
2050 CMP #&30:BCC LF9B1 :\ <'0', exit
2060 CMP #&3A:BCC LF9A0 :\ '0'..'9', add to accumulator
2070 AND #&DF:SBC #&07:BCC LF9B1:\ Convert letter, if <'A', exit
2080 CMP #&40:BCS LF9B1 :\ >'F', exit
2090 .LF9A0
2100 ASL A:ASL A:ASL A:ASL A :\ *16
2110 LDX #&03 :\ Prepare to move 3+1 bits
2120 .LF9A6
2130 ASL A:ROL &F0:ROL &F1 :\ Move bits into accumulator
2140 DEX:BPL LF9A6 :\ Loop for four bits, no overflow check
2150 INY:BNE LF98C :\ Move to next character
2160 .LF9B1
2170 RTS
2180
2190
2200 \ Send string to Tube R2
2210 \ ======================
2220 .SendString
2230 STX &F8:STY &F9 :\ Set &F8/9=>string
2240 .SendStringF8
2250 LDY #&00
2260 .LF9B8
2270 BIT TubeS2:BVC LF9B8 :\ Wait for Tube R2 free
2280 LDA (&F8),Y:STA TubeR2 :\ Send character to Tube R2
2290 INY:CMP #&0D:BNE LF9B8 :\ Loop until <cr> sent
2300 LDY &F9:RTS :\ Restore Y from &F9 and return
2310
2320
2330 \ OSCLI - Execute command
2340 \ =======================
2350 \ On entry, XY=>command string
2360 \ On exit, XY= preserved
2370 \
2380 .osCLI
2390 PHA:STX &F8:STY &F9 :\ Save A, &F8/9=>command string
2400 LDY #&00
2410 .LF9D1
2420 JSR SkipSpaces:INY
2430 CMP #ASC"*":BEQ LF9D1 :\ Skip spaces and stars
2440 AND #&DF:TAX :\ Ignore case, and save in X
2450 LDA (&F8),Y :\ Get next character
2460 CPX #ASC"G":BEQ CmdGO :\ Jump to check '*GO'
2470 CPX #ASC"H":BNE osCLI_IO :\ Not "H---", jump to pass to Tube
2480 CMP #ASC".":BEQ CmdHELP :\ "H.", jump to do *DELETEHIMEM
2490 AND #&DF :\ Ignore case
2500 CMP #ASC"E":BNE osCLI_IO :\ Not "HE---", jump to pass to Tube
2510 INY:LDA (&F8),Y :\ Get next character
2520 CMP #ASC".":BEQ CmdHELP :\ "HE.", jump to do *DELETEHIMEM
2530 AND #&DF :\ Ignore case
2540 CMP #ASC"L":BNE osCLI_IO :\ Not "HEL---", jump to pass to Tube
2550 INY:LDA (&F8),Y :\ Get next character
2560 CMP #ASC".":BEQ CmdHELP :\ "HEL.", jump to do *DELETEHIMEM
2570 AND #&DF :\ Ignore case
2580 CMP #ASC"P":BNE osCLI_IO :\ Not "HELP---", jump to pass to Tube
2590 INY:LDA (&F8),Y :\ Get next character
2600 AND #&DF :\ Ignore case
2610 CMP #ASC"A":BCC CmdHELP :\ "HELP" terminated by non-letter, do *DELETEHIMEM
2620 CMP #ASC"[":BCC osCLI_IO :\ "HELP" followed by letter, pass to Tube
2630
2640 \ *Help - Display help information
2650 \ --------------------------------
2660 .CmdHELP
2670 JSR PrText :\ Print help message
2680 EQUB 10:EQUB 13:EQUS "6502 TUBE 1.10"
2690 EQUB 10:EQUB 13
2700 NOP :\ Continue to pass '*DELETEHIMEM' command to Tube
2710
2720
2730 \ OSCLI - Send command line to host
2740 \ =================================
2750 \ On entry, &F8/9=>command string
2760 \
2770 \ Tube data &02 string &0D -- &7F or &80
2780 \
2790 .osCLI_IO
2800 LDA #&02:JSR SendCommand :\ Send command &02 - OSCLI
2810 JSR SendStringF8 :\ Send command string at &F8/9
2820 .osCLI_Ack
2830 JSR WaitByte :\ Wait for acknowledgement
2840 CMP #&80:BEQ LFA5C :\ Jump if code to be entered
2850 PLA:RTS :\ Restore A and return
2860
2870
2880 \ *GO - call machine code
2890 \ -----------------------
2900 .CmdGO
2910 AND #&DF :\ Ignore case
2920 CMP #ASC"O":BNE osCLI_IO :\ Not '*GO', jump to pass to Tube
2930 JSR SkipSpaces1 :\ Move past any spaces
2940 JSR ScanHex:JSR SkipSpaces :\ Read hex value and move past spaces
2950 CMP #&0D:BNE osCLI_IO :\ More parameters, pass to Tube to deal with
2960 TXA:BEQ LFA5C :\ If no address given, jump to current program
2970 LDA &F0:STA &F6 :\ Set program start to address read
2980 LDA &F1:STA &F7
2990
3000 .LFA5C
3010 LDA &EF:PHA:LDA &EE:PHA :\ Save current program
3020 JSR EnterCode
3030 PLA:STA &EE:STA &F2 :\ Restore current program and
3040 PLA:STA &EF:STA &F3 :\ set address top of memory to it
3050 PLA:RTS
3060
3070 .CheckAck
3080 BEQ osCLI_Ack
3090
3100
3110 \ OSBYTE - Byte MOS functions
3120 \ ===========================
3130 \ On entry, A, X, Y=OSBYTE parameters
3140 \ On exit, A preserved
3150 \ If A<&80, X=returned value
3160 \ If A>&7F, X, Y, Carry=returned values
3170 \
3180 .osBYTE
3190 CMP #&80:BCS ByteHigh :\ Jump for long OSBYTEs
3200 \
3210 \ Tube data &04 X A -- X
3220 \
3230 PHA:LDA #&04
3240 .LFA7A
3250 BIT TubeS2:BVC LFA7A :\ Wait for Tube R2 free
3260 STA TubeR2 :\ Send command &04 - OSBYTELO
3270 .LFA82
3280 BIT TubeS2:BVC LFA82 :\ Wait for Tube R2 free
3290 STX TubeR2:PLA :\ Send single parameter
3300 .LFA8B
3310 BIT TubeS2:BVC LFA8B :\ Wait for Tube R2 free
3320 STA TubeR2 :\ Send function
3330 .LFA93
3340 BIT TubeS2:BPL LFA93 :\ Wait for Tube R2 data present
3350 LDX TubeR2:RTS :\ Get return value
3360
3370 .ByteHigh
3380 CMP #&82:BEQ Byte82 :\ Read memory high word
3390 CMP #&83:BEQ Byte83 :\ Read bottom of memory
3400 CMP #&84:BEQ Byte84 :\ Read top of memory
3410 \
3420 \ Tube data &06 X Y A -- Cy Y X
3430 \
3440 PHA:LDA #&06
3450 .LFAAB
3460 BIT TubeS2:BVC LFAAB :\ Wait for Tube R2 free
3470 STA TubeR2 :\ Send command &06 - OSBYTEHI
3480 .LFAB3
3490 BIT TubeS2:BVC LFAB3 :\ Wait for Tube R2 free
3500 STX TubeR2 :\ Send parameter 1
3510 .LFABB
3520 BIT TubeS2:BVC LFABB :\ Wait for Tube R2 free
3530 STY TubeR2 :\ Send parameter 2
3540 PLA
3550 .LFAC4
3560 BIT TubeS2:BVC LFAC4 :\ Wait for Tube R2 free
3570 STA TubeR2 :\ Send function
3580 CMP #&8E:BEQ CheckAck :\ If select language, check to enter code
3590 CMP #&9D:BEQ LFAEF :\ Fast return with Fast BPUT
3600 PHA :\ Save function
3610 .LFAD5
3620 BIT TubeS2:BPL LFAD5 :\ Wait for Tube R2 data present
3630 LDA TubeR2:ASL A:PLA :\ Get Carry
3640 .LFADF
3650 BIT TubeS2:BPL LFADF :\ Wait for Tube R2 data present
3660 LDY TubeR2 :\ Get return high byte
3670 .LFAE7
3680 BIT TubeS2:BPL LFAE7 :\ Wait for Tube R2 data present
3690 LDX TubeR2 :\ Get return low byte
3700 .LFAEF
3710 RTS
3720
3730 .Byte84:LDX &F2:LDY &F3:RTS :\ Read top of memory from &F2/3
3740 .Byte83:LDX #&00:LDY #&08:RTS :\ Read bottom of memory
3750 .Byte82:LDX #&00:LDY #&00:RTS :\ Return &0000 as memory high word
3760
3770
3780 \ OSWORD - Various functions
3790 \ ==========================
3800 \ On entry, A =function
3810 \ XY=>control block
3820 \
3830 .osWORD
3840 STX &F8:STY &F9 :\ &F8/9=>control block
3850 TAY:BEQ RDLINE :\ OSWORD 0, jump to read line
3860 PHA:LDY #&08
3870 .LFB09
3880 BIT TubeS2:BVC LFB09 :\ Loop until Tube R2 free
3890 STY TubeR2 :\ Send command &08 - OSWORD
3900 .LFB11
3910 BIT TubeS2:BVC LFB11 :\ Loop until Tube R2 free
3920 STA TubeR2 :\ Send function
3930 TAX:BPL WordSendLow :\ Jump with functions<&80
3940 LDY #&00:LDA (&F8),Y :\ Get send block length from control block
3950 TAY:JMP WordSend :\ Jump to send control block
3960
3970 .WordSendLow
3980 LDY WordLengthsLo-1,X :\ Get send block length from table
3990 CPX #&15:BCC WordSend :\ Use this length for OSWORD 1 to &14
4000 LDY #&10 :\ Send 16 bytes for OSWORD &15 to &7F
4010 .WordSend
4020 BIT TubeS2:BVC WordSend :\ Wait until Tube R2 free
4030 STY TubeR2 :\ Send send block length
4040 DEY:BMI LFB45 :\ Zero or &81..&FF length, nothing to send
4050 .LFB38
4060 BIT TubeS2:BVC LFB38 :\ Wait for Tube R2 free
4070 LDA (&F8),Y:STA TubeR2 :\ Send byte from control block
4080 DEY:BPL LFB38 :\ Loop for number to be sent
4090 .LFB45
4100 TXA:BPL WordRecvLow :\ Jump with functions<&80
4110 LDY #&01:LDA (&F8),Y :\ Get receive block length from control block
4120 TAY:JMP WordRecv :\ Jump to receive control block
4130
4140 .WordRecvLow
4150 LDY WordLengthsHi-1,X :\ Get receive length from table
4160 CPX #&15:BCC WordRecv :\ Use this length for OSWORD 1 to &14
4170 LDY #&10 :\ Receive 16 bytes for OSWORD &15 to &7F
4180 .WordRecv
4190 BIT TubeS2:BVC WordRecv :\ Wait for Tube R2 free
4200 STY TubeR2 :\ Send receive block length
4210 DEY:BMI LFB71 :\ Zero of &81..&FF length, nothing to receive
4220 .LFB64
4230 BIT TubeS2:BPL LFB64 :\ Wait for Tube R2 data present
4240 LDA TubeR2:STA (&F8),Y :\ Get byte to control block
4250 DEY:BPL LFB64 :\ Loop for number to receive
4260 .LFB71
4270 LDY &F9:LDX &F8:PLA :\ Restore registers
4280 RTS
4290
4300
4310 \ RDLINE - Read a line of text
4320 \ ============================
4330 \ On entry, A =0
4340 \ XY=>control block
4350 \ On exit, A =undefined
4360 \ Y =length of returned string
4370 \ Cy=0 ok, Cy=1 Escape
4380 \
4390 \ Tube data &0A block -- &FF or &7F string &0D
4400 \
4410 .RDLINE
4420 LDA #&0A:JSR SendCommand :\ Send command &0A - RDLINE
4430 LDY #&04
4440 .LFB7E
4450 BIT TubeS2:BVC LFB7E :\ Wait for Tube R2 free
4460 LDA (&F8),Y:STA TubeR2 :\ Send control block
4470 DEY:CPY #&01:BNE LFB7E :\ Loop for 4, 3, 2
4480 LDA #&07:JSR SendByte :\ Send &07 as address high byte
4490 LDA (&F8),Y:PHA :\ Get text buffer address high byte
4500 DEY
4510 .LFB96
4520 BIT TubeS2:BVC LFB96 :\ Wait for Tube R2 free
4530 STY TubeR2 :\ Send &00 as address low byte
4540 LDA (&F8),Y:PHA :\ Get text buffer address low byte
4550 LDX #&FF:JSR WaitByte :\ Wait for response
4560 CMP #&80:BCS RdLineEscape :\ Jump if Escape returned
4570 PLA:STA &F8:PLA:STA &F9 :\ Set &F8/9=>text buffer
4580 LDY #&00
4590 .RdLineLp
4600 BIT TubeS2:BPL RdLineLp :\ Wait for Tube R2 data present
4610 LDA TubeR2:STA (&F8),Y :\ Store returned character
4620 INY:CMP #&0D:BNE RdLineLp :\ Loop until <cr>
4630 LDA #&00:DEY:CLC:INX :\ Return A=0, Y=len, X=00, Cy=0
4640 RTS
4650 :
4660 .RdLineEscape
4670 PLA:PLA:LDA #&00 :\ Return A=0, Y=len, X=FF, Cy=1
4680 RTS
4690
4700
4710 \ OSARGS - Read info on open file
4720 \ ===============================
4730 \ On entry, A =function
4740 \ X =>data word in zero page
4750 \ Y =handle
4760 \ On exit, A =returned value
4770 \ X preserved
4780 \ Y preserved
4790 \
4800 \ Tube data &0C handle block function -- result block
4810 \
4820 .osARGS
4830 PHA:LDA #&0C:JSR SendCommand :\ Send command &0C - OSARGS
4840 .LFBD2
4850 BIT TubeS2:BVC LFBD2 :\ Loop until Tube R2 free
4860 STY TubeR2 :\ Send handle
4870 LDA &03,X:JSR SendByte :\ Send data word
4880 LDA &02,X:JSR SendByte
4890 LDA &01,X:JSR SendByte
4900 LDA &00,X:JSR SendByte
4910 PLA:JSR SendByte :\ Send function
4920 JSR WaitByte:PHA :\ Get and save result
4930 JSR WaitByte:STA &03,X :\ Receive data word
4940 JSR WaitByte:STA &02,X
4950 JSR WaitByte:STA &01,X
4960 JSR WaitByte:STA &00,X
4970 PLA:RTS :\ Get result back and return
4980
4990
5000 \ OSFIND - Open of Close a file
5010 \ =============================
5020 \ On entry, A =function
5030 \ Y =handle or XY=>filename
5040 \ On exit, A =zero or handle
5050 \
5060 \ Tube data &12 function string &0D -- handle
5070 \ &12 &00 handle -- &7F
5080 \
5090 .osFIND
5100 PHA:LDA #&12:JSR SendCommand :\ Send command &12 - OSFIND
5110 PLA:JSR SendByte :\ Send function
5120 CMP #&00:BNE OPEN :\ If <>0, jump to do OPEN
5130 PHA:TYA:JSR SendByte :\ Send handle
5140 JSR WaitByte:PLA:RTS :\ Wait for acknowledge, restore regs and return
5150 .OPEN
5160 JSR SendString :\ Send pathname
5170 JMP WaitByte :\ Wait for and return handle
5180
5190
5200 \ OSBGet - Get a byte from open file
5210 \ ==================================
5220 \ On entry, H =handle
5230 \ On exit, A =byte Read
5240 \ H =preserved
5250 \ Cy set if EOF
5260 \
5270 \ Tube data &0E handle -- Carry byte
5280 \
5290 .osBGET
5300 LDA #&0E:JSR SendCommand :\ Send command &0E - OSBGET
5310 TYA:JSR SendByte :\ Send handle
5320 JMP WaitCarryChar :\ Jump to wait for Carry and byte
5330
5340
5350 \ OSBPut - Put a byte to an open file
5360 \ ===================================
5370 \ On entry, A =byte to write
5380 \ Y =handle
5390 \ On exit, A =preserved
5400 \ Y =preserved
5410 \
5420 \ Tube data &10 handle byte -- &7F
5430 \
5440 .osBPUT
5450 PHA:LDA #&10:JSR SendCommand :\ Send command &10 - OSBPUT
5460 TYA:JSR SendByte :\ Send handle
5470 PLA:JSR SendByte :\ Send byte
5480 PHA:JSR WaitByte:PLA:RTS :\ Wait for acknowledge and return
5490
5500
5510 \ Send a byte to Tube R2
5520 \ ======================
5530 .SendCommand
5540 .SendByte
5550 BIT TubeS2:BVC SendByte :\ Wait for Tube R2 free
5560 STA TubeR2:RTS :\ Send byte to Tube R2
5570
5580
5590 \ OSFILE - Operate on whole files
5600 \ ===============================
5610 \ On entry, A =function
5620 \ XY=>control block
5630 \ On exit, A =result
5640 \ control block updated
5650 \
5660 \ Tube data &14 block string <cr> function -- result block
5670 \
5680 .osFILE
5690 STY &FB:STX &FA :\ &FA/B=>control block
5700 PHA:LDA #&14:JSR SendCommand :\ Send command &14 - OSFILE
5710 LDY #&11
5720 .LFC5F
5730 LDA (&FA),Y:JSR SendByte :\ Send control block
5740 DEY:CPY #&01:BNE LFC5F :\ Loop for &11..&02
5750 DEY:LDA (&FA),Y:TAX
5760 INY:LDA (&FA),Y:TAY :\ Get pathname address to XY
5770 JSR SendString :\ Send pathname
5780 PLA:JSR SendByte :\ Send function
5790 JSR WaitByte:PHA :\ Wait for result
5800 LDY #&11
5810 .LFC7E
5820 JSR WaitByte:STA (&FA),Y :\ Get control block back
5830 DEY:CPY #&01:BNE LFC7E :\ Loop for &11..&02
5840 LDY &FB:LDX &FA :\ Restore registers
5850 PLA:RTS :\ Get result and return
5860
5870
5880 \ OSGBPB - Multiple byte Read and write
5890 \ =====================================
5900 \ On entry, A =function
5910 \ XY=>control block
5920 \ On exit, A =returned value
5930 \ control block updated
5940 \
5950 \ Tube data &16 block function -- block Carry result
5960 \
5970 .osGBPB
5980 STY &FB:STX &FA :\ &FA/B=>control block
5990 PHA:LDA #&16:JSR SendCommand :\ Send command &16 - OSGBPB
6000 LDY #&0C
6010 .LFC9A
6020 LDA (&FA),Y:JSR SendByte :\ Send control block
6030 DEY:BPL LFC9A :\ Loop for &0C..&00
6040 PLA:JSR SendByte :\ Send function
6050 LDY #&0C
6060 .LFCA8
6070 JSR WaitByte:STA (&FA),Y :\ Get control block back
6080 DEY:BPL LFCA8 :\ Loop for &0C..&00
6090 LDY &FB:LDX &FA :\ Restore registers
6100 JMP WaitCarryChar :\ Jump to get Carry and result
6110
6120
6130 .Unsupported
6140 BRK:EQUB 255:EQUS "Bad":EQUB 0
6150
6160
6170 \ OSWORD control block lengths
6180 \ ============================
6190 .WordLengthsLo
6200 EQUB &00:EQUB &05:EQUB &00:EQUB &05
6210 EQUB &02:EQUB &05:EQUB &08:EQUB &0E
6220 EQUB &04:EQUB &01:EQUB &01:EQUB &05
6230 EQUB &00:EQUB &01:EQUB &20:EQUB &10
6240 EQUB &0D:EQUB &00:EQUB &04:EQUB &80
6250 .WordLengthsHi
6260 EQUB &05:EQUB &00:EQUB &05:EQUB &00
6270 EQUB &05:EQUB &00:EQUB &00:EQUB &00
6280 EQUB &05:EQUB &09:EQUB &05:EQUB &00
6290 EQUB &08:EQUB &18:EQUB &00:EQUB &01
6300 EQUB &0D:EQUB &80:EQUB &04:EQUB &80
6310
6320
6330 \ Interrupt Handler
6340 \ =================
6350 .InterruptHandler
6360 STA &FC:PLA:PHA :\ Save A, get flags from stack
6370 AND #&10:BNE BRKHandler :\ If BRK, jump to BRK handler
6380 JMP (IRQ1V) :\ Continue via IRQ1V handler
6390
6400 .IRQ1Handler
6410 BIT TubeS4:BMI LFD3F :\ If data in Tube R4, jump to process errors and transferes
6420 BIT TubeS1:BMI LFD18 :\ If data in Tube R1, jump to process Escape and Events
6430 JMP (IRQ2V) :\ Pass on to IRQ2V
6440
6450 .BRKHandler
6460 TXA:PHA :\ Save X
6470 TSX:LDA &0103,X :\ Get address from stack
6480 CLD:SEC:SBC #&01:STA &FD
6490 LDA &0104,X:SBC #&00:STA &FE :\ &FD/E=>after BRK opcode
6500 PLA:TAX:LDA &FC :\ Restore X, get saved A
6510 CLI:JMP (BRKV) :\ Restore IRQs, jump to Error Handler
6520
6530
6540 \ Interrupt generated by data in Tube R1
6550 \ --------------------------------------
6560 .LFD18
6570 LDA TubeR1:BMI LFD39 :\ b7=1, jump to set Escape state
6580 TYA:PHA:TXA:PHA :\ Save registers
6590 JSR LFE80:TAY :\ Get Y parameter from Tube R1
6600 JSR LFE80:TAX :\ Get X parameter from Tube R1
6610 JSR LFE80 :\ Get event number from Tube R1
6620 JSR LFD36:PLA:TAX:PLA:TAY :\ Dispatch event, restore registers
6630 LDA &FC:RTI :\ Restore A, return from interrupt
6640 .LFD36
6650 JMP (EVNTV)
6660 .LFD39
6670 ASL A:STA &FF :\ Set Escape flag from b6
6680 LDA &FC:RTI :\ Restore A, return from interrupt
6690
6700
6710 \ Interrupt generated by data in Tube R4
6720 \ --------------------------------------
6730 .LFD3F
6740 LDA TubeR4:BPL LFD65 :\ b7=0, jump for data transfer
6750 CLI
6760 .LFD45
6770 BIT TubeS2:BPL LFD45 :\ Wait for data in Tube R2
6780 LDA TubeR2
6790 LDA #&00:STA ERRBUF:TAY :\ Store BRK opcode in error buffer
6800 JSR WaitByte:STA ERRBUF+1 :\ Get error number
6810 .LFD59
6820 INY:JSR WaitByte :\ Store bytes fetched from Tube R2
6830 STA ERRBUF+1,Y:BNE LFD59 :\ Loop until final zero
6840 JMP ERRBUF :\ Jump to error block to generate error
6850
6860 \ Data transfer initiated by IRQ via Tube R4
6870 \ ------------------------------------------
6880 .LFD65
6890 STA NMIV+0:TYA:PHA :\ Save transfer type, save Y
6900 LDY NMIV+0 :\ Get transfer type back
6910 LDA LFE70,Y:STA NMIV+0 :\ get NMI routine address from table
6920 LDA LFE78,Y:STA NMIV+1 :\ and point NMIV to it
6930 LDA LFE60,Y:STA &F4 :\ Point &F4/5 to transfer address field
6940 LDA LFE68,Y:STA &F5
6950 .LFD83
6960 BIT TubeS4:BPL LFD83 :\ Wait until Tube R4 data present
6970 LDA TubeR4 :\ Get called ID from Tube R4
6980 CPY #&05:BEQ LFDE7 :\ If 'TubeRelease', jump to exit
6990 TYA:PHA:LDY #&01 :\ Save transfer type
7000 .LFD93
7010 BIT TubeS4:BPL LFD93 :\ Wait for Tube R4 data present
7020 LDA TubeR4 :\ Fetch and disgard address byte 4
7030 .LFD9B
7040 BIT TubeS4:BPL LFD9B :\ Wait for Tube R4 data present
7050 LDA TubeR4 :\ Fetch and disgard address byte 3
7060 .LFDA3
7070 BIT TubeS4:BPL LFDA3 :\ Wait for Tube R4 data present
7080 LDA TubeR4:STA (&F4),Y:DEY :\ Fetch address byte 2, store in address
7090 .LFDAE
7100 BIT TubeS4:BPL LFDAE :\ Wait for Tube R4 data present
7110 LDA TubeR4:STA (&F4),Y :\ Fetch address byte 1, store in address
7120 BIT TubeR3:BIT TubeR3 :\ Read from Tube R3 twice
7130 .LFDBE
7140 BIT TubeS4:BPL LFDBE :\ Wait for Tube R4 data present
7150 LDA TubeR4:PLA :\ Get sync byte from Tube R4
7160 CMP #&06:BCC LFDE7 :\ Exit if not 256-byte transfers
7170 BNE LFDEC :\ Jump with 256-byte read
7180
7190 \ Send 256 bytes to Tube via R3
7200 \ -----------------------------
7210 LDY #&00
7220 .LFDCF
7230 LDA TubeS3:AND #&80:BPL LFDCF:\ Wait for Tube R3 free
7240 .NMI6Addr
7250 LDA &FFFF,Y:STA TubeR3 :\ Fetch byte and send to Tube R3
7260 INY:BNE LFDCF :\ Loop for 256 bytes
7270 .LFDDF
7280 BIT TubeS3:BPL LFDDF :\ Wait for Tube R3 free
7290 STA TubeR3 :\ Send final sync byte
7300 .LFDE7
7310 PLA:TAY:LDA &FC:RTI :\ Restore registers and return
7320
7330 \ Read 256 bytes from Tube via R3
7340 \ -------------------------------
7350 .LFDEC
7360 LDY #&00
7370 .LFDEE
7380 LDA TubeS3:AND #&80:BPL LFDEE:\ Wait for Tube R3 data present
7390 LDA TubeR3 :\ Fetch byte from Tube R3
7400 .NMI7Addr
7410 STA &FFFF,Y:INY:BNE LFDEE :\ Store byte and loop for 256 bytes
7420 BEQ LFDE7 :\ Jump to restore registers and return
7430
7440 \ Transfer 0 - Transfer single byte to Tube
7450 \ -----------------------------------------
7460 .NMI0
7470 PHA :\ Save A
7480 .NMI0Addr
7490 LDA &FFFF:STA TubeR3 :\ Get byte and send to Tube R3
7500 INC NMI0Addr+1:BNE LFE0F :\ Increment transfer address
7510 INC NMI0Addr+2
7520 .LFE0F
7530 PLA:RTI :\ Restore A and return
7540
7550 \ Transfer 1 - Transfer single byte from Tube
7560 \ -------------------------------------------
7570 .NMI1
7580 PHA:LDA TubeR3 :\ Save A, get byte from Tube R3
7590 .NMI1Addr
7600 STA &FFFF :\ Store byte
7610 INC NMI1Addr+1:BNE LFE20 :\ Increment transfer address
7620 INC NMI1Addr+2
7630 .LFE20
7640 PLA:RTI :\ Restore A and return
7650
7660 \ Transfer 2 - Transfer two bytes to Tube
7670 \ ---------------------------------------
7680 .NMI2
7690 PHA:TYA:PHA:LDY #&00 :\ Save registers
7700 LDA (&F6),Y:STA TubeR3 :\ Get byte and send to Tube R3
7710 INC &F6:BNE LFE32:INC &F7 :\ Increment transfer address
7720 .LFE32
7730 LDA (&F6),Y:STA TubeR3 :\ Get byte and send to Tube R3
7740 INC &F6:BNE LFE3D:INC &F7 :\ Increment transfer address
7750 .LFE3D
7760 PLA:TAY:PLA:RTI :\ Restore registers and return
7770
7780 \ Transfer 3 - Transfer two bytes from Tube
7790 \ -----------------------------------------
7800 .NMI3
7810 PHA:TYA:PHA:LDY #&00 :\ Save registers
7820 LDA TubeR3:STA (&F6),Y :\ Get byte from Tube R3 and store
7830 INC &F6:BNE LFE51:INC &F7 :\ Increment transfer address
7840 .LFE51
7850 LDA TubeR3:STA (&F6),Y :\ Get byte from Tube R3 and store
7860 INC &F6:BNE LFE5C:INC &F7 :\ Increment transfer address
7870 .LFE5C
7880 PLA:TAY:PLA:RTI :\ Restore registers and return
7890
7900 \ Data transfer address pointers
7910 \ ------------------------------
7920 .LFE60
7930 EQUB (NMI0Addr+1) AND 255:EQUB (NMI1Addr+1) AND 255
7940 EQUB &00F6 AND 255 :EQUB &00F6 AND 255
7950 EQUB &00F6 AND 255 :EQUB &00F6 AND 255
7960 EQUB (NMI6Addr+1) AND 255:EQUB (NMI7Addr+1) AND 255
7970 .LFE68
7980 EQUB (NMI0Addr+1) DIV 256:EQUB (NMI1Addr+1) DIV 256
7990 EQUB &00F6 DIV 256 :EQUB &00F6 DIV 256
8000 EQUB &00F6 DIV 256 :EQUB &00F6 DIV 256
8010 EQUB (NMI6Addr+1) DIV 256:EQUB (NMI7Addr+1) DIV 256
8020
8030 \ Data transfer routine addresses
8040 \ -------------------------------
8050 .LFE70
8060 EQUB NMI0 AND 255 :EQUB NMI1 AND 255
8070 EQUB NMI2 AND 255 :EQUB NMI3 AND 255
8080 EQUB NMI_Ack AND 255:EQUB NMI_Ack AND 255
8090 EQUB NMI_Ack AND 255:EQUB NMI_Ack AND 255
8100 .LFE78
8110 EQUB NMI0 DIV 256 :EQUB NMI1 DIV 256
8120 EQUB NMI2 DIV 256 :EQUB NMI3 DIV 256
8130 EQUB NMI_Ack DIV 256:EQUB NMI_Ack DIV 256
8140 EQUB NMI_Ack DIV 256:EQUB NMI_Ack DIV 256
8150
8160
8170 \ Wait for byte in Tube R1 while allowing requests via Tube R4
8180 \ ============================================================
8190 .LFE80
8200 BIT TubeS1:BMI LFE94 :\ If data in Tube R1, jump to fetch it
8210 .LFE85
8220 BIT TubeS4 :\ Check if data present in Tube R4
8230 BPL LFE80 :\ If nothing there, jump back to check Tube R1
8240 LDA &FC :\ Save IRQ's A store in A register
8250 PHP:CLI:PLP :\ Allow an IRQ through to process R4 request
8260 STA &FC:JMP LFE80 :\ Restore IRQ's A store and jump back to check R1
8270 .LFE94
8280 LDA TubeR1:RTS :\ Fetch byte from Tube R1 and return
8290
8300
8310 \ Print embedded string
8320 \ =====================
8330 .PrText
8340 PLA:STA &FA:PLA:STA &FB :\ &FA/B=>embedded string
8350 LDY #&00
8360 .LFEA0
8370 INC &FA:BNE LFEA6:INC &FB :\ Increment address
8380 .LFEA6
8390 LDA (&FA),Y:BMI LFEB0 :\ Get character, exit if >&7F
8400 JSR OSWRCH:JMP LFEA0 :\ Print character and loop back for more
8410 .LFEB0
8420 JMP (&00FA) :\ Jump back to code after string
8430
8440
8450 \ Null NMI code
8460 \ -------------
8470 .NMI_Ack
8480 STA TubeR3:RTI :\ Store to TubeR3 to acknowlege NMI
8490
8500
8510 \ Spare space
8520 \ ===========
8530 EQUS STRING$(&FEF0-P%,CHR$255)
8540
8550
8560 \ I/O Space
8570 \ =========
8580 EQUS STRING$(8,CHR$0)
8590
8600 \ Tube I/O Registers
8610 \ ==================
8620 .TubeS1 :\ &FEF8 :EQUB 0
8630 .TubeR1 :\ &FEF9 :EQUB 0
8640 .TubeS2 :\ &FEFA :EQUB 0
8650 .TubeR2 :\ &FEFB :EQUB 0
8660 .TubeS3 :\ &FEFC :EQUB 0
8670 .TubeR3 :\ &FEFD :EQUB 0
8680 .TubeS4 :\ &FEFE :EQUB 0
8690 .TubeR4 :\ &FEFF :EQUB 0
8700
8710
8720 \ Spare space
8730 \ ===========
8740 .LFF00
8750 EQUS STRING$(&FF80-P%,CHR$255)
8760
8770
8780 \ DEFAULT VECTOR TABLE
8790 \ ====================
8800 .LFF80
8810 EQUW Unsupported :\ &200 - USERV
8820 EQUW ErrorHandler :\ &202 - BRKV
8830 EQUW IRQ1Handler :\ &204 - IRQ1V
8840 EQUW Unsupported :\ &206 - IRQ2V
8850 EQUW osCLI :\ &208 - CLIV
8860 EQUW osBYTE :\ &20A - BYTEV
8870 EQUW osWORD :\ &20C - WORDV
8880 EQUW osWRCH :\ &20E - WRCHV
8890 EQUW osRDCH :\ &210 - RDCHV
8900 EQUW osFILE :\ &212 - FILEV
8910 EQUW osARGS :\ &214 - ARGSV
8920 EQUW osBGET :\ &216 - BGetV
8930 EQUW osBPUT :\ &218 - BPutV
8940 EQUW osGBPB :\ &21A - GBPBV
8950 EQUW osFIND :\ &21C - FINDV
8960 EQUW Unsupported :\ &21E - FSCV
8970 EQUW NullReturn :\ &220 - EVNTV
8980 EQUW Unsupported :\ &222 - UPTV
8990 EQUW Unsupported :\ &224 - NETV
9000 EQUW Unsupported :\ &226 - VduV
9010 EQUW Unsupported :\ &228 - KEYV
9020 EQUW Unsupported :\ &22A - INSV
9030 EQUW Unsupported :\ &22C - RemV
9040 EQUW Unsupported :\ &22E - CNPV
9050 EQUW NullReturn :\ &230 - IND1V
9060 EQUW NullReturn :\ &232 - IND2V
9070 EQUW NullReturn :\ &234 - IND3V
9080
9090 .VECDEF :\ &FFB6 :EQUB &36:EQUW LFF80
9100 .OSXXXX :\ &FFB9 :JMP Unsupported
9110 .OSXXXX :\ &FFBC :JMP Unsupported
9120 .OSXXXX :\ &FFBF :JMP Unsupported
9130 .OSXXXX :\ &FFC2 :JMP Unsupported
9140 .OSXXXX :\ &FFC5 :JMP Unsupported
9150 .NVRDCH :\ &FFC8 :JMP osRDCH
9160 .NVWRCH :\ &FFCB :JMP osWRCH
9170
9180 .OSFIND :\ &FFCE :JMP (FINDV)
9190 .OSGBPB :\ &FFD1 :JMP (GBPBV)
9200 .OSBPUT :\ &FFD4 :JMP (BPutV)
9210 .OSBGET :\ &FFD7 :JMP (BGetV)
9220 .OSARGS :\ &FFDA :JMP (ARGSV)
9230 .OSFILE :\ &FFDD :JMP (FILEV)
9240
9250 .OSRDCH :\ &FFE0 :JMP (RDCHV)
9260 .OSASCI :\ &FFE3 :CMP #&0D:BNE OSWRCH
9270 .OSNEWL :\ &FFE7 :LDA #&0A:JSR OSWRCH
9280 .OSWRCR :\ &FFEC :LDA #&0D
9290 .OSWRCH :\ &FFEE :JMP (WRCHV)
9300 .OSWORD :\ &FFF1 :JMP (WORDV)
9310 .OSBYTE :\ &FFF4 :JMP (BYTEV)
9320 .OS_CLI :\ &FFF7 :JMP (CLIV)
9330
9340 .NMIV :\ &FFFA :EQUW NMI0 :\ NMI Vector
9350 .RESETV :\ &FFFC :EQUW RESET :\ RESET Vector
9360 .IRQV :\ &FFFE :EQUW InterruptHandler :\ IRQ Vector
9370 ]:NEXT
9380 OSCLI"Save Client "+STR$~mcode%+" "+STR$~O%+" "+STR$~load%+" "+STR$~load%
9390 ON ERROR ON ERROR OFF:END
9400 *Quit
Re: Matchbox sized 6502 Co Processor
Dave,
One of the things that I have been thinking about with respect to my similar project is how to simulate the VHDL code. The problem being that the second processor has to live in isolation from a host machine. Or do you run a simulation of a host machine as well..?
One of the things that I have been thinking about with respect to my similar project is how to simulate the VHDL code. The problem being that the second processor has to live in isolation from a host machine. Or do you run a simulation of a host machine as well..?
Re: Matchbox sized 6502 Co Processor
I guess it depends on how much you want to try to simulate. I've written a simple test bench that simulates a few writes to the tube registers from the host side, which is enough to initialize things and force a parasite reset:jms2 wrote:One of the things that I have been thinking about with respect to my similar project is how to simulate the VHDL code. The problem being that the second processor has to live in isolation from a host machine. Or do you run a simulation of a host machine as well..?
https://github.com/hoglet67/CoPro6502/b ... tBench.vhd
This was enough to allow me to test the Co Processor 6502 seems to be able to execute code, and test the bootstrap code. But not really to test the data transfer.
To go further, you would need a real 6502 on the host side as well, executing real code.
My plan is to now try the real hardware, and only go back to the simulation when it doesn't work
Dave
Re: Matchbox sized 6502 Co Processor
That's really amazingly small.
Your advantage with the bbc is that most of the software is already available. On the Atom we have barely random access files ready and the rest is still unwritten...
There are many interesting projects going on here
Your advantage with the bbc is that most of the software is already available. On the Atom we have barely random access files ready and the rest is still unwritten...
There are many interesting projects going on here
FPGAtom: 512 KB RAM, Real Time Clock and 64 colours
MAN WOMAN
MAN WOMAN
- richardtoohey
- Posts: 4075
- Joined: Thu Dec 29, 2011 5:13 am
- Location: Tauranga, New Zealand
- Contact:
Re: Matchbox sized 6502 Co Processor
You can say that again!roland wrote:There are many interesting projects going on here
I read the first one and go "that's interesting, must have a closer look to see what the clever people have done" and then the second and third and fourth projects come out and I've got no chance!
Not that I need to get distracted by any other projects, got enough projects of my own that I've started and then put down.
But great to see what you are all up to!
Re: Matchbox sized 6502 Co Processor
Dave,
in your Tube code on github, are there any changes from the version that Ed uploaded to his site or is it just a clone?
I ask because I took Ed's out of date code and fixed a few bugs (it turned out Ed had also fixed these but not release) and I wondered if your insights into ULA reversing had lead to any further improvements.
I also heavily modified Ed's code to give a true synchronous interface to a 6502 core that didn't interface precisely like a physical one (all the timings are different).
What I want to do is cut a version that has that synchronous interface on the "best known good" drop of Tube code so that I can offer my monolithic tube PCB out to the masses. Tidying up the last few tube interface bugs was the last thing to do and I ran out of steam a bit.
Once I'm happy it's all working I'll pop whole design up for everyone (including open source PCB).
J
in your Tube code on github, are there any changes from the version that Ed uploaded to his site or is it just a clone?
I ask because I took Ed's out of date code and fixed a few bugs (it turned out Ed had also fixed these but not release) and I wondered if your insights into ULA reversing had lead to any further improvements.
I also heavily modified Ed's code to give a true synchronous interface to a 6502 core that didn't interface precisely like a physical one (all the timings are different).
What I want to do is cut a version that has that synchronous interface on the "best known good" drop of Tube code so that I can offer my monolithic tube PCB out to the masses. Tidying up the last few tube interface bugs was the last thing to do and I ran out of steam a bit.
Once I'm happy it's all working I'll pop whole design up for everyone (including open source PCB).
J
Re: Matchbox sized 6502 Co Processor
Hi all,
A bit more progress to report....
Today I made a small PCB to connect the GOP module to the Tube: The two headers are to allow easy connection of the signals to a logic analyzer for debugging.
As expected, it didn't work first time....
There was no (beebmaster) smoke, but the boot sequence was hanging, unless the DFS ROM was disabled.
After a bit of debugging with the logic analyzer, I could see lots of ram reads and writes, and the bootmode signal going low after 1ms. Then I noticed that the parasite IRQ line was being held low all the time, which didn't seem right.
Looking at how this is generated in Tube.v, it looks to me the logic was the wrong way around:
So I changed it to this:
And low and behold, it lives!!!
I don't have many second processor programs to test with, but I do have a disc of Level 9 adventure games:
Now, there are still several issues to work through:
1. When first powered up, it hangs at A, requiring a control Break: I suspect this is just because the Xilinx is taking longer to load it's configuration that the Beeb takes to boot.
2. Tube Elite doesn't work - it load the splash screen and the main program but then hangs: 3. It doesn't work in a Master 128 - it is recognised and you get BASIC printed, and sometimes some garbage, but the > prompt never appears. The machine is not hung, because caps lock still works. But I can't get any further.
But this all seems very promising.
Ed, do any of the above issues sound familiar?
Dave
A bit more progress to report....
Today I made a small PCB to connect the GOP module to the Tube: The two headers are to allow easy connection of the signals to a logic analyzer for debugging.
As expected, it didn't work first time....
There was no (beebmaster) smoke, but the boot sequence was hanging, unless the DFS ROM was disabled.
After a bit of debugging with the logic analyzer, I could see lots of ram reads and writes, and the bootmode signal going low after 1ms. Then I noticed that the parasite IRQ line was being held low all the time, which didn't seem right.
Looking at how this is generated in Tube.v, it looks to me the logic was the wrong way around:
Code: Select all
assign p_irq_b = ( (h_reg0_q_r[`I_IDX] & p_data_available_w[0]) | (h_reg0_q_r[`J_IDX] & p_data_available_w[3]) ) ? `P_INTERRUPT_OFF_D : 1'b0;
Code: Select all
assign p_irq_b = ( (h_reg0_q_r[`I_IDX] & p_data_available_w[0]) | (h_reg0_q_r[`J_IDX] & p_data_available_w[3]) ) ? 1'b0 : `P_INTERRUPT_OFF_D ;
1. When first powered up, it hangs at A, requiring a control Break: I suspect this is just because the Xilinx is taking longer to load it's configuration that the Beeb takes to boot.
2. Tube Elite doesn't work - it load the splash screen and the main program but then hangs: 3. It doesn't work in a Master 128 - it is recognised and you get BASIC printed, and sometimes some garbage, but the > prompt never appears. The machine is not hung, because caps lock still works. But I can't get any further.
But this all seems very promising.
Ed, do any of the above issues sound familiar?
Dave
Re: Matchbox sized 6502 Co Processor
Great work Dave! My memory is fallible, but here's a timeline of some of our observations:
https://sites.google.com/site/beeb816/to-dos
which do tally up with some of yours. For sure when we experimented with different TTL families to buffer our GODIL Tube to the host machine, we got different kinds of failures, some of which were statistical. From our records:
https://sites.google.com/site/beeb816/file-cabinet
I can't explain that.
We experimented also with the optional pullup/pulldowns the FPGA can implement internally, and with the voltage standard it can adhere to (LVTTL or HCMOS33) - we found that no pullup, no pulldown, LVTTL was successful for the Beeb's external Tube interface and for the Master's internal copro interface. It seems we didn't try the Master's external interface - at least, we didn't record a result.
Great to see you got so far so quickly!
Hope this helps
Ed
https://sites.google.com/site/beeb816/to-dos
which do tally up with some of yours. For sure when we experimented with different TTL families to buffer our GODIL Tube to the host machine, we got different kinds of failures, some of which were statistical. From our records:
It's odd that we got anything to work given your need to bugfix p_irq_b - it seems not to be fixed in our latest code drop atFailure Types
FAIL (1) Tube recognized, banner message appears but hang following announcement of ROMs (can sometimes boot to '*' prompt)
FAIL (2) Tube not recognized at all and system comes up as if coprocessor absent.
FAIL (3) Unreliable boot to BASIC or '*' prompt
FAIL(4) Unreliable boot: ctrl break hangs, break unreliably boots to '*' (~80%)
https://sites.google.com/site/beeb816/file-cabinet
I can't explain that.
We experimented also with the optional pullup/pulldowns the FPGA can implement internally, and with the voltage standard it can adhere to (LVTTL or HCMOS33) - we found that no pullup, no pulldown, LVTTL was successful for the Beeb's external Tube interface and for the Master's internal copro interface. It seems we didn't try the Master's external interface - at least, we didn't record a result.
Great to see you got so far so quickly!
Hope this helps
Ed
Re: Matchbox sized 6502 Co Processor
Ed,
Regarding p_irq_b, if you look at the older version of the code on your site (tube.20100606T1943.tgz), the bug is not present:
So it looks like a regression, rather than something that was always there.
Dave
Regarding p_irq_b, if you look at the older version of the code on your site (tube.20100606T1943.tgz), the bug is not present:
Code: Select all
assign p_irq_b = ( (h_reg0_q_r[`I_IDX] & p_data_available_w[0]) | (h_reg0_q_r[`J_IDX] & p_data_available_w[3]) ) ? 1'b0 : `P_INTERRUPT_OFF_D;
Dave
Re: Matchbox sized 6502 Co Processor
That explains it! Thanks.
Re: Matchbox sized 6502 Co Processor
Nice job, Dave. Again
Greetings,
Roland
Can't you make my new Atom board? That would be a lot quicker than makePCBToday I made a small PCB to connect the GOP module to the Tube
Greetings,
Roland
FPGAtom: 512 KB RAM, Real Time Clock and 64 colours
MAN WOMAN
MAN WOMAN
Re: Matchbox sized 6502 Co Processor
I'll have a go if you can do a single sided layoutroland wrote:Can't you make my new Atom board? That would be a lot quicker than makePCB
Dave
Re: Matchbox sized 6502 Co Processor
I'm frustrated that it won't run Elite....
I've updated the T65 core to be a 65C02 and the Tube ROM to be the 65C102 version from JGH's site. But this made no difference (not that I really expected it to).
I've had a look with the logic analyzer, and the host seems to be very busy endlessly reading register 1 then register 0. What's interesting is that if I look at the parasite side, it's not writing to the tube at all. So it looks like there may be a problem here with 24 byte FIFO that is register 1.
This is normally used for OSWRCH from the parasite to the host, but it's possible that Elite uses it for something else, or that it is pushing much more data through this.
I think this is going to be very tricky to diagnose.....
Dave
I've updated the T65 core to be a 65C02 and the Tube ROM to be the 65C102 version from JGH's site. But this made no difference (not that I really expected it to).
I've had a look with the logic analyzer, and the host seems to be very busy endlessly reading register 1 then register 0. What's interesting is that if I look at the parasite side, it's not writing to the tube at all. So it looks like there may be a problem here with 24 byte FIFO that is register 1.
This is normally used for OSWRCH from the parasite to the host, but it's possible that Elite uses it for something else, or that it is pushing much more data through this.
I think this is going to be very tricky to diagnose.....
Dave
Re: Matchbox sized 6502 Co Processor
I've just noticed that the 24 byte FIFO is actually only a 1 byte FIFO in Rich/Ed's tube design.
I wonder if Elite for some reason needs more that just 1 byte.
But that still wouldn't explain the behaviour I'm seeing on the host, continuously reading tube address 0 (register 1 status) and 1 (register 1 data).
What's weird is that if you look at the values being returned:
- Read address 0 -> 0x4F (register 1 status)
- Read address 1 -> 0x41 (register 1 data)
Looking at the Tube App Note, a 0x4F in register 1 status means:
- A1=0 - there is no data available in register 1
- F1=1 - register 1 is not full
If there is no data available, I don't understand why the host goes on to read the data register.
Dave
I wonder if Elite for some reason needs more that just 1 byte.
But that still wouldn't explain the behaviour I'm seeing on the host, continuously reading tube address 0 (register 1 status) and 1 (register 1 data).
What's weird is that if you look at the values being returned:
- Read address 0 -> 0x4F (register 1 status)
- Read address 1 -> 0x41 (register 1 data)
Looking at the Tube App Note, a 0x4F in register 1 status means:
- A1=0 - there is no data available in register 1
- F1=1 - register 1 is not full
If there is no data available, I don't understand why the host goes on to read the data register.
Dave
Re: Matchbox sized 6502 Co Processor
Tomorrow, I'll do a diff on my code from Ed's and see if any of my fixes need to be merged in and if they might help solve any of your issues.
I've also been round the IRQ polarity loop, but some others too.
Jason
I've also been round the IRQ polarity loop, but some others too.
Jason
Re: Matchbox sized 6502 Co Processor
Hi Jason,
Sorry, I somehow managed to miss your post earlier.
I spotted the IRQ polarity bug this afternoon.
The only other thing I spotted during the reverse engineering was that the R3 N flag wasn't being correctly generated. See this post:
http://www.stardot.org.uk/forums/viewto ... =60#p93314
I've fixed this, but it made no difference to Elite.
If there is any other behaviour you are uncertain about, I have a full gate level simulation of the reverse engineered Tube design running.
Are you able to run Tube Elite on your version?
In the mean time, I mighy have a go at a Z80 second processor using the T80 core:
http://opencores.org/project,t80
Looks like the boot mode logic is slightly more complicated, as it flips the ROM back in when handing an NMI interrupt.
Dave
Sorry, I somehow managed to miss your post earlier.
It was the latest version from his site.flynnjs wrote:Dave,
in your Tube code on github, are there any changes from the version that Ed uploaded to his site or is it just a clone?
I ask because I took Ed's out of date code and fixed a few bugs (it turned out Ed had also fixed these but not release) and I wondered if your insights into ULA reversing had lead to any further improvements.
I spotted the IRQ polarity bug this afternoon.
The only other thing I spotted during the reverse engineering was that the R3 N flag wasn't being correctly generated. See this post:
http://www.stardot.org.uk/forums/viewto ... =60#p93314
I've fixed this, but it made no difference to Elite.
If there is any other behaviour you are uncertain about, I have a full gate level simulation of the reverse engineered Tube design running.
That would be most helpful.flynnjs wrote:Tomorrow, I'll do a diff on my code from Ed's and see if any of my fixes need to be merged in and if they might help solve any of your issues.
I've also been round the IRQ polarity loop, but some others too.
Are you able to run Tube Elite on your version?
In the mean time, I mighy have a go at a Z80 second processor using the T80 core:
http://opencores.org/project,t80
Looks like the boot mode logic is slightly more complicated, as it flips the ROM back in when handing an NMI interrupt.
Dave
Re: Matchbox sized 6502 Co Processor
Jason,
I hope you don't mind me posting this link to the OSHUG (Open Source Hardware User Group) talk you did at the end of last year about your 6502 FPGA Second Processor project:
https://www.youtube.com/watch?v=2hcSdu4DHD4
Well worth listening to.
Dave
I hope you don't mind me posting this link to the OSHUG (Open Source Hardware User Group) talk you did at the end of last year about your 6502 FPGA Second Processor project:
https://www.youtube.com/watch?v=2hcSdu4DHD4
Well worth listening to.
Dave
Re: Matchbox sized 6502 Co Processor
Thanks for sharing Jason's talk Dave! I should clarify that Rich is responsible for virtually all the code in our Tube model, whereas I'm responsible for all mistakes in merging updates for the recent releases.
Note that John Kortink's ReTuLa also only has a single byte for the 24-byte FIFO. But I don't know whether or not it runs Elite. I do know he's said that the short FIFO should only cause a small performance loss - and we measured about 2% (see below.)
I found that "Stephen", a commenter on Mike Stirling's Beeb-on-FPGA article, also wrote an HDL Tube which did everything except run Elite. He said:
Cheers
Ed
Note that John Kortink's ReTuLa also only has a single byte for the 24-byte FIFO. But I don't know whether or not it runs Elite. I do know he's said that the short FIFO should only cause a small performance loss - and we measured about 2% (see below.)
I found that "Stephen", a commenter on Mike Stirling's Beeb-on-FPGA article, also wrote an HDL Tube which did everything except run Elite. He said:
Dave, as you've been able to see the parasite-side Tube activity during the livelock, could you also see the address bus, enough to find out which bit of OS code is running on the parasite?Can you try the following for me on your FPGA model.This seems to cause a hard interrupt lock up for me about a 10th of a second after i do it. This is whats breaking elite tube for me.Code: Select all
*FX 9,0
Cheers
Ed
The Sphere benchmark times were:
No coprocessor, Master 128 - 24.1s
Internal 65C102 Coprocessor @ 4Mhz, with original tube IC - 10.93s
Internal 65C102 Coprocessor @ 4Mhz, with our tube replacement FPGA - 11.18s
Our current implementation has the following configuration:Code: Select all
10 TIME=0 15 MODE 4 20 CLS 30 S%=400 40 VDU29,640;512; 50 MOVE 0,0 60 FOR A=0 TO 126 STEP.25:DRAW S%*SINA,S%*COSA*SIN(A*.95):NEXT 70 PRINT TIME/100
So a little over 2% difference compared with the original which has a 24 byte FIFO in the p->h direction for Reg1.Code: Select all
Host-> Parasite Parasite->host Reg1 1 byte 1 byte Reg2 1 byte 1 byte Reg3 2 byte 2 byte Reg4 1 byte 1 byte
Re: Matchbox sized 6502 Co Processor
In terms of debugging, I have the following pins available to me:BigEd wrote:Dave, as you've been able to see the parasite-side Tube activity during the livelock, could you also see the address bus, enough to find out which bit of OS code is running on the parasite?
- 7 TP pins on the GOP module test connector (TP2..
- 6 spare pins on the DIP
This is probably just about enough to be able to see the relevant parasite address.
At the moment I'm tinkering with a Z80 core.
My plan was to wait for Jason to post his fixes, and see if they resolve the Elite issue, and if not, I'll dig in further.
Dave
Re: Matchbox sized 6502 Co Processor
haha, I threw that talk together about a week after I got my first boot using Ed's Tube code and one of the cores I mentioned. It was after that that I discovered a number of other issues and I've not touched/fixed anything since!
Did anyone go to the last talk, October 2014? That was a sort of follow up, on OS processors and verification.
Thanks for clarifying how many mods you've made. I've got some down-time today so I'll explore my changes and post back later.
Did anyone go to the last talk, October 2014? That was a sort of follow up, on OS processors and verification.
Thanks for clarifying how many mods you've made. I've got some down-time today so I'll explore my changes and post back later.
- BeebMaster
- Posts: 7380
- Joined: Sun Aug 02, 2009 5:59 pm
- Location: Lost in the BeebVault!
- Contact:
Re: Matchbox sized 6502 Co Processor
What is the blue tint in the screenshots? Is it deliberate? I rather like it!
Re: Matchbox sized 6502 Co Processor
It's just the way the monitor is when you are slightly off axis.BeebMaster wrote:What is the blue tint in the screenshots? Is it deliberate? I rather like it!
Dave
Re: Matchbox sized 6502 Co Processor
This morning I've been trying to put together a Z80 second processor using the same hardware.
I've got it to the point when it is recognised and outputs it's name during the boot sequence: But it's then hanging where I think it should be saying insert system disk.
At least, that's what BeebMasters's seems to say at this point:
http://www.beebmaster.co.uk/2P/AcornZ80-11.html
I'll look at the Client ROM to source to try to figure our where it's getting stuck.
If I remove the BBC Basic ROM, I can get to a * prompt.
Can anyone point me at a version of Z80 basic I can load into Sideways ROM?
Dave
I've got it to the point when it is recognised and outputs it's name during the boot sequence: But it's then hanging where I think it should be saying insert system disk.
At least, that's what BeebMasters's seems to say at this point:
http://www.beebmaster.co.uk/2P/AcornZ80-11.html
I'll look at the Client ROM to source to try to figure our where it's getting stuck.
If I remove the BBC Basic ROM, I can get to a * prompt.
Can anyone point me at a version of Z80 basic I can load into Sideways ROM?
Dave
Re: Matchbox sized 6502 Co Processor
Looks like there's a BBC BASIC ROM in BBCTube.zip as found at
http://mdfs.net/Software/BBCBasic/CPMTube/
courtesy of JGH and RIchard Russell.
http://mdfs.net/Software/BBCBasic/CPMTube/
courtesy of JGH and RIchard Russell.
Re: Matchbox sized 6502 Co Processor
Won't that still need CP/M to handle the low level I/O?
d.
d.
Re: Matchbox sized 6502 Co Processor
As I understand it, this version has been patched to remove the dependency on CP/M, and to allow for a ROM version.
(See http://goo.gl/Mndt86)
(See http://goo.gl/Mndt86)
Re: Matchbox sized 6502 Co Processor
OK, I've tried this Z80 Basic ROM and it still hangs during boot.BigEd wrote:As I understand it, this version has been patched to remove the dependency on CPM, and to allow for a ROM version.
If I disable all language ROMs and do a control break, I get a * prompt.
If I then do a *HELP DFS, then it hangs half way through the expected output.
If I instead I do a *HELP XXX, then it completes (less output). But if I do it again, it hangs.
Looks like it is hanging after outputting about 60 characters.
I think I'll wait for Jason's fixed to the tube code, and see if these help.
Dave
Re: Matchbox sized 6502 Co Processor
OK, the hanging on *HELP is caused by the output to printer being enabled.
If I do a ^C, then *HELP never hangs.
Pressing Escape causes an immediate hang of the parasite, and the parasite IRQ line goes low and stays low.
So, possibly I have a problem with interrupt handling on the parasite.
Dave
If I do a ^C, then *HELP never hangs.
Pressing Escape causes an immediate hang of the parasite, and the parasite IRQ line goes low and stays low.
So, possibly I have a problem with interrupt handling on the parasite.
Dave
Re: Matchbox sized 6502 Co Processor
I took a bit of a break this afternoon and have just come back, and immediately spotted a silly mistake in generating P_CS_B.
On correcting this, I'm getting a bit further, but it now seems there is a problem with NMI.
When NMI is asserted (0), I see the following:
- two writes to RAM (as the return address is pushed onto the stack)
- boot mode entered (as an instruction is read from 0x0066)
- boot mode exited (as an instuction is read from >= 0x8000)
- a single access to the tube
At this point, I would expect NMI to go back to (1), but it doesn't, and it seems to stay low for ever.
I'm guessing this is a tube bug. Or, I've somehow messed to the NMI handling, and the wrong address is being jumped to.
Jason, I'd really appreciate a copy of your fixed up tube code!
Dave
On correcting this, I'm getting a bit further, but it now seems there is a problem with NMI.
When NMI is asserted (0), I see the following:
- two writes to RAM (as the return address is pushed onto the stack)
- boot mode entered (as an instruction is read from 0x0066)
- boot mode exited (as an instuction is read from >= 0x8000)
- a single access to the tube
At this point, I would expect NMI to go back to (1), but it doesn't, and it seems to stay low for ever.
I'm guessing this is a tube bug. Or, I've somehow messed to the NMI handling, and the wrong address is being jumped to.
Jason, I'd really appreciate a copy of your fixed up tube code!
Dave