XEP80


Manual#

ATR-Image#

Drivers#

Images#

Original Atari XEP80 Boot Disk DX5087 Label (C) 1987 Atari

The XEP 80 - Part 1#

by Erhard Pütz (aka Atreju aka Floppydoc)
prepared and translated by Mathy v. Nisselroy

Ever since the 1993 ABBUC Annual meeting (Jahreshauptversammlung) I've been working with the XEP 80 and gained quite a bit of knowledge and experience. I've used the XEP under BASIC, MAC65, BobTerm and from DOS to read texts.

At this time I want to ask everybody who's got information not mentioned in the manual, to send it to me. I'm especially interested in Information about the Hardware. Like, what graphicsprocessor as used?

While working with the XEP some very annoying things cought my attention. First there is this constant need to switch video plugs. Really nerve recking is readjusting of screen height, horizontal screen position and brightness. The height of the screen is almost right when the XEP is working in the American TV-standard with 50 Hz. But then the screen flickers and who knows how long the monitor will put up with the imposed 60 Hz. I once read that the higher screen frequency increases the current in the coils (Comment by Mathy: I don't quite know what these coils are called in English, but the direct the electronic beams that draw the picture on your cathode ray tube (according to this booklet I have)). This increases the load on both the electronics, which might not be designed handle this higher current, and the coils, which might burn out.

After switching to 50 Hz though, the screen is significantly higher than the standard XL/XE screen, pushing both upper and lower parts of the graphics off the screen. And the characters look really course. Once readjusted, one is rewarded with a good 80 character screen.

Speed #

I've heard people say, the XEP would be slow. Well, when I print text to the XEP screen (X:) (original device driver), it rushes by so fast I hardly have time to press Ctrl-1 to halt the screen. Slow you say? Absolutely not, rather fast actually, in my opinion much faster then the original screen editor (E:). So I tried out some demo's. So this is it, they really are slow. But why? For is purpose I printed out one of the BASIC-listings and read through it. And read it again, and again, and again... Oh my God, who committed this crime...Oops, programmed this. At that time I didn't understand the programm, but it was one big chaos and even on the first glance one would find the slowest BASIC solutions. So, I'm gonna cut this thing short and state: the XEP 80 is fast. And thiss is mentioned in the manual really: Data transfer speed between XEP and computer takes place at 15.7 kBit. That's quite fast, but why this rare number? Why not 19.2 kBit? In that case the XEP would be able to keep up with the highest transfer rate of BobTerm. And why on the other hand, can the XEP only keep up with speeds of 4800 baud under BobTerm, where it should at least get 9600 baud? Let's start with the number 15.7 kBit. This means 15700 bits per second. The duration of one bit in this case is approximately 63.7us (micro seconds = 10^-6 or 0.000001 sec.). The time the microcessor in our computer needs to execute a command is measured in cycles. With the Atari 8bit every cycle takes approximately .564 us. One bit therefore takes about 113 cycles. The execution of command takes 2 to 7 cycles. While one bit is send, the computer could execute 16 to 56 commands. Let's use an average of 35. Then we can say one thing for sure: our 8 bitter can handle a transfer rate of 15.7 kBit hands down. Back to the question why it only works up to 4800 baud under BobTerm. Here's part of the XEP driver (V1.2) for BobTerm

LDX #$00          ; Load X with zero
SEI               ; don't execute IRQ's
STX $D40E         ; disable NMI's
STA WSYNC         ; pause
STX PORTA         ; send startbit
STA WSYNC         ; pause
STA PORTA         ; send bit 0
ROR               ; next bit
STA WSYNC         ; pause
STA PORTA         ; send bit 1
ROR               ; next bit
STA WSYNC         ; pause
STA PORTA         ; send bit 2
ROR               ; next bit
STA WSYNC         ; pause
STA PORTA         ; send bit 3
ROR               ; next bit
STA WSYNC         ; pause
STA PORTA         ; send bit 4
ROR               ; next bit
STA WSYNC         ; pause
STA PORTA         ; send bit 5
ROR               ; next bit
STA WSYNC         ; pause
STA PORTA         ; send bit 6
ROR               ; next bit
STA WSYNC         ; pause
STA PORTA         ; send bit 7
ROR               ; next bit
STA WSYNC         ; pause
STA PORTA         ; send Mode bit
LDA #$FF
STA WSYNC         ; pause
STA PORTA         ; send stopbit
STA $D40E         ; enable NMI's
CLI               ; IRQ's permitted
LDX #$20          ; wait 90 us
DEX
BPL LOOP
LDA PORTA         ; read XEP status
AND #Mask         ; ($02 or $20)
BEQ Busy          ; XEP not ready yet
RTS               ; ready, 1 byte sent

Everywere, where it reads "pause" the computer does the following: NOTHING. This command tells the computer it should halt the microprocessor until one screen line is processed. This seems to take up as much time as one bit at 15.7 kBit, or 63.7 microseconds. This command was issued 11 times, add to that the 166 cycles in the 90 us waiting loop, where the computer can't do much either. This makes 866 cycles or maximum 431, on average 250 commands, the computer can not execute, just because it is halted. The data BobTerm receives via the RS232 interface however, come in faster then it can be processed. The data not processed in time are lost. And this only because the computer is busy doing nothing while transfering data to the XE. How could one change this and why could the XEP print to screen even faster yet? The computer has to the whole job, like for instance preparing the next byte that should be send to the XEP, in the time between 2 bytes. But what if the next byte to be send would instantaneously be available? The computer should get it from the buffer or wherever, while 1 byte is send to the XEP. To achieve this, the byte should be automatically - without the CPU having anything to do with it - be send and this is done by HARDWARE. Such a device is built into the computer and calls itself POKEY. That's the chip that, among other things, handles the datatraffic with your disk drive, printer and cassette. If we then think about how fast the data transfer with a disk drive can be, namely 51 kBit/s th a Speedy or even 78 kBit/s with the HSS Copier (Mathy: both are German hardware upgrades for the 1050 disk drive), it becomes clear what advantages there are to use a hardware solution.

As far I can see, POKEY can not be used for datatrafficing with the XEP, because the XEP uses 9 bit data words during data transfer, where POKEY only uses 8 bits. A standard SIO chip, like the 6551, do it. The nineth bit, used to distinguish between data and commands, could be emulated by the parity bit. And here the 6551 has five possibilities: None, odd, even, mark and space parity. How we would handle the nineth bit when the computer receives it is one of the things I have to think about, but it should be possible. So we take an EPROM, in which we place the new XEP 80 driver, a bit of electronics to decode some signals, a 6551 and a triple DIP switch. The DIP switch is used to select a device number (Mathy: Hm, nice idea! Where have I heard that one before :-)) and connect the whole thing to the parallel bus of the XL/XE. For the electrical engineers among you I have to add that the XL/XE first of al needs a couple of powerfull bus drivers in the shape of two 74AS244 and one 74AS245, especially if you're running a BlackBox!

The memory map of the driver:#

The driver for the XEP 80 basically exists of two parts. One of those parts is a so called Relocator, meaning, it moves the main programm to the top of the memory. Now I've recently worked with TurboWord+ und while reading the manual, I bumped into something strange. The driver of the XEP 80 should be called AUTORUN.SYS under TurboWord+ and SpartaDOS, because otherwise the MEMHI would be too low. Read it, tried it, seen it. But why? With AUTORUN.SYS, MEMHI is set at $95FF, when run by hand with XEP80 (RETURN) or from a batch file, it's set at $8FFF. I accepted it for a long time, but since it kept bugging me, I checked into this. I'm not gonna tell you how. But what came out will knock you off your sock When run by hand, the driver will install itself twice. But only the last one installed will be used. And it installs itself twice, because the file XEP80 ends with an INIT address, instead of a RUN address. DOS jumps to the INIT address ($2E2) after loading the file and when returning, tries to jump to the RUN address. But since there is none, it jumps to the beginning of the file, which starts the relocator once again. Using a disk monitor, I changed INIT to RUN and that was it. I was rewarded with 1.5 kByte more free memory.

RESET#

One thing you can not do is press RESET or otherwise cause a warm start. A warm start will reinitialise the device drivers, including the XEP 80 driver. One would think that all values are entere again, but the value for MEMHI is NOT entered. Sigh, those programmers at ATARI, real pro's. But even they can forget some things. However, after a warm start, MEMHI is set to the start of the play list. With BASIC this is $9C1F. If you now fill up the memory nicely, you'll eventually overwrite the XEP driver, which is located between $9600 and $9C1F. If at this point you press RESET again, not even DOS will be reinitialised and you will be unable to save anything. And that's by far not all. Small error, big results. Well, that's about all I want to say about the XEP 80 for now, but the text is over 10 kByte anyhow. Maybe it's even usefull to somebody. I'm always happy to get an echo.

Greetings, your Floppydoc - Erhard Puetz

The XEP 80 part two#

When I said in my previous article that I would be please about an echo, I meant, I would be pleased with ANY echo, not ONE echo. But I shouldn't complain, better ONE echo than NO echo at all. The echo said to me: Erhard, after I read you article about the XEP 80 in the ABBUC magazine (Mathy: number 38), I pulled my XEP 80 out of the drawer. I've always wanted to use it with BobTerm, but since the XEP driver for BobTerm doesn't switch the XEP to the German (Mathy: ahem, I thought it was called the European or PAL) standard, I've always had a flickering, too small image. Can't we do something about that?

Sure, I say, one takes the XIO command that sets the XEP 80 to the 50 Hz standard, turns that into a small machine language program and loads it as AUTORUN.SYS before BobTerm - Just a moment, this wont gonna work this way. There is no XEP driver initialised yet, making the XIO command disappear into thin air. OK, first the XEP driver, then the XIO command, then BobTerm... Hmmm, won't work either. The XEP driver for BobTerm isn't hooked to the normal editor.

And, BobTerm loads and initializes the driver. - Think, Think, Think - The driver contains the subroutine for sending data to the XEP. That's the part we talked about in the previous article (Mathy: ABBUC magazine 38). Here is the address data for the driver: memory from $4000 to $422E and RUN $4001. Ah yes, this should work. At the end of the files, before the RUN address, I append a small routine and redirect the RUN address to it.

This is what that looks like:

$422F   SEC           ; A command is send
$4230   LDA #$D7      ; the number $D7 sets the XEP to 50 Hz in textmode
$4232   JSR $4145     ; That's the point where the Send-routine starts
$4235   JMP $4001     ; driver installed
       .ORG $02E0     ; RUN vector
       .WORD $422F    ; RUN address

Try it, it works. During all these try outs, I've searched through the XEP driver several times, and that's when I saw that the Send-outine starts a bit earlier than I told you last month. It starts like this:

$4139  X_DAT CLC          ; Data will be send
$413A        .BYTE
$413B  X_DAT SEC          ; A command is send
$413C        PHP          ; Get Carry status
$413D  WAIT_3 LDX VCOUNT  ; Number of just created image divided by two
$4140  CPX #$6B           ; Equal or greater than 107
$4142  BCS WAIT_3         ; Yes, then wait
$4144  PLP                ; return Carry Status
$4145  ROR                ; shift byte to the right until
$4146  ROR                ; bit 0 is send first.
$4147  ROR
$4148  ROR
$4149  ROR

... And this is where the part from the article in magzine 8 continues.

What do my square eyes see there? An other way that's that suppose to do? Well, boldly said, it's not allowed to send data during the Vertical Blank. But it's not clear to me why. The VBI is disabled anyhow. Might the WSYNC register in the "austastluecke" (Mathy: some kind of interval. Maybe I'll know what this word means when I translate the next article about the XEP, should Erhard write more of them. :-) ) not deliver the apropriate timing? Let's try that. Starting with $413D I'll just write the NOP command 7 times. We're still losing time, but at least we're not waiting 50 times a second. So, loaded BobTerm with the changed driver and - Look at that. All of a sudden BobTerm works with the XEP 80 at 9600 baud, not just 4800. I've tried it out a bit more, but could not find any negative side effects. So I called the ABBUC BBS and looky here, works like a charm. With my chest raised in pride I called the ABBUCcian that had laid this task upon me. I've ooen it, I've done it, I said, not just the 50 Hz, but even 9600 baud.

The day before yesterday was the day that I decided to show off my newly gained knowledge in ABBUC magazine. So I called Wolfgang (Mathy: Wolfgang Burger is the president of ABBUC and previous SysOp of the ABBUC BBS) to ask him, if he would in interested in a sequel to the XEP 80 article. Sure, he said, opening up the way to help the ever information hungry ABBUCcians. And here's a little more, just to make sure you don't starve.

For $40E0 on, we have 13 bytes, with which the XEP is initialized:

value function
$D9 Cursor always on
$D4 Use ATASCII characterset
$DE Bright characters on dark background
$D3 Burst mode, no cursor data is send back
$60 Left Margin 0 low nibble
$70 Left Margin 0 Hi nibble
$AF Right Margin low nibble 15 + 4*16 Hi nibble = 79
$B4 Right Margin hi nibble
$00 Horizontal cursor position = 0
$80 vertical cursor position = 0
$D0 Erase List flag
$C5 Fill RAM with SPACE-characters
$DC Set Scroll window to X-cursor position

Since all this trail and error stuff started to annoy me, I "just for a minute" reassembled the driver, so I now a fairly readable file to work with. This means I'm gonna write more articles about the XEP 80. Since I was able to delve up more information about the XEP 80, I can already tell you: the 19200 baud are in reachable distance and I seem to be on a hot trail with my suspiciouns about the 6551 SIO chip from the first article (I think).

DEEPER DUNGEONS#

The videocontroller inside the XEP 80 is a 48 pin chip. It's data bus is 16 bits wide on the video side. This way, two RAMs could be read simultaniously, one containing the text that should be displayed and another containing the text attributes. There are eight possible attributes:

attribute display
Inverse A character plus it's surrounding area is display "Inverse"
Halve Bright The character in displayed with a lower brightness. Other options are a higher brightness and even color.
Flickering On, Off, On, Off
Double Height Text in double height, internally some conditions have to be met though.
Double Width Text in double wide. The next line can't be displayed though, so we have to leave a blank line between two lines of character
Underlined An apparently freely defined character is mixed in. This can be the "underline" character or an "overline" or "strait through the middle" character or whatever you want
Hidden The text is not displayed at all. This attribute should also be set when using a double height character, so the controller knows that this is the bottom halve of the double height haracter.
Graphics Since this is an attribute, text and blockgraphics can be mixed at will. Except double height, all other attributes can be used at the same time

And then there is the Graphics mode of the XEP 80. Just like the subject of block graphics, it's a very broad subject and will not be discussed here.

THE LIGHT PEN#

The controller offers the option of connecting a lightpen to it. Via interrupts, the horizontal and vertical positions are stored into two registers. HPEN is 7 bit wide (128 positions) and VPEN is 5 bit wide (32 positions). Since this does not provide us with a very high resolution, we can forget about drawing with a light pen.

THE SERIAL INTERFACE#

Here we find a UART (Universal Asynchronus Receiver Transmitter), that, in it's addresses and functions, equals the good old 6551 so much, that I'm assuming it is. With a 4 bit pre-devider, the system clock (12MHz in the XEP 80) is devided into one of 16 steps. These steps are 3.4, 4, 4.5, ... ,11. The actual baudrate devider is 11 bits wide and is further devided by 16 at the output. In the XEP 80 the baudrate is set to 15625. The mathematics could however also look like this:

12 MHz     : 6.5 = approximately 1.8432 MHz
12 MHz     : 6.5 = approximately 1.8432 MHz

1.8432 MHz : 6   = 307200 Hz
1.8432 MHz : 3   = 614400 Hz

307200 Hz  : 16  = 19.200 kHz
614400 Hz  : 16  = 38.400 kHz

Those 19.200 kHz lies within manufacturers specifications. If 38.400kHz works, is something someone should try out. But since the dividers aren't used up yet (we can even go much faster), why won't it work.

That's it for this time.

Greetings, your FloppyDoc

The Original ATARI XEP 80 Handler Source#

Handler Source#

0100 ;.OPT NOLIST
0110  .OPT NOEJECT
0120 ;
0130 BASE=$6000
0140 ;
0150 ;CHAR EQUATES
0160 ;
0170 LF=10
0180 CR=13
0190 ESC=$1B
0200 SPACE=$20
0210 CNTL=$5E
0220 CLS=$7D
0230 EOL=$9B
0240 ;
0250 ;80 COL COMMANDS
0260 ;
0270 XCH80=$50
0280 LMG80=$60
0290 LMH80=$70
0300 YCR80=$80
0310 SGR80=$99
0320 PAG80=$9A
0330 RMG80=$A0
0340 RMH80=$B0
0350 GET80=$C0
0360 CUR80=$C1
0370 RST80=$C2
0380 PST80=$C3
0390 CLR80=$C4
0400 LIS80=$D0
0410 SCR80=$D2
0420 SCB80=$D3
0430 GRF80=$D4
0440 ICM80=$D5
0450 PAL80=$D7
0460 CRS80=$D9
0470 MCF80=$DB
0480 PNT80=$DD
0490 ;
0500 ;MEMORY EQUATES
0510 ;
0520 DOSINI=$0C
0530 ICDNOZ=$21
0540 ICCOMZ=$22
0550 ICAX1Z=$2A
0560 ICAX2Z=$2B
0570 ICIDNO=$2E
0580 LMARGN=$52
0590 RMARGN=$53
0600 VCP=$54
0610 HCP=$55
0620 IN=$CC
0630 CDTMV3=$21C
0640 SDMCTL=$22F
0650 KEYDEL=$2D9
0660 KEYREP=$2DA
0670 DVSTAT=$2EA
0680 CRSINH=$2F0
0690 CHBAS=$2F4
0700 LISTF=$2FE
0710 SFLAG=$2FF
0720 HATABS=$31A
0730 ICDNO=$341
0740 ICCOM=$342
0750 PAL=$D014
0760 IRQEN=$D20E
0770 SKSTAT=$D20F
0780 PORTA=$D300
0790 PACTL=$D302
0800 DMACTL=$D400
0810 WSYNC=$D40A
0820 VCOUNT=$D40B
0830 NMIEN=$D40E
0840 ;
0850  *=BASE-2
0860 ;
0870  .WORD CEND-BEGIN ;RELOCATER INFO
0880 ;
0890 BEGIN JSR ERTS ;DOSINI VECTOR
0900  JMP CINIT ;RELOCATER JUMP
0910 ;
0920 PAUX1 .BYTE 0
0930 PAUX2 .BYTE 0
0940 ;
0950 READ JSR DISAB;DISABLE IRQ INTS
0960  LDA #GET80
0970  JSR CINP ;REQUEST, GET CHAR
0980  PHA ;SAVE CHAR
0990  JSR INPUT ;GET CURS
1000  JSR CURCK ;CHECK FOR X>$4F
1010  PLA ;RESTORE CHAR
1020  JMP ENAB
1030 ;
1040 CINP JSR CMD
1050 INPUT LDA #00 ;TIME CRITICAL CODE
1060  TAX ;MUST NOT CROSS A
1070  LDY #31 ;PAGE BOUNDARY
1080  STA DATIN
1090 IN0 LDA PORTA ;4
1100  AND INMSK ;4
1110  BEQ IN01 ;3 IF A 0, 2 IF NOT
1120  DEX
1130  BNE IN0
1140  DEY ;TIMEOUT LOOPS
1150  BNE IN0
1160  SEC ;NO RESPONSE
1170  RTS
1180 IN01 LDX #08
1190  LDY #12 ;2
1200 IN1 DEY
1210  BNE IN1 ;5*Y-1
1220  NOP ;2
1230 IN10 LDY #15 ;2 MAIN DLY COUNT
1240 IN2 DEY
1250  BNE IN2 ;5*Y-1
1260  LDA PORTA ;4 GET BYTE
1270  AND INMSK ;4 GET BIT
1280  CLC ;2
1290  BEQ IN25 ;0=3,1=2
1300  SEC ;1=2
1310 IN25 BCC IN26 ;0=3,1=2
1320 IN26 DEX ;2 DEC COUNT
1330  BMI IN3 ;2 (3 DONE)
1340  ROR DATIN ;6 SHIFT IN BIT
1350  BCC IN10 ;3 ALWAYS
1360 IN3 LDY #15 ;DELAY 1/2 BIT
1370 IN33 DEY
1380  BNE IN33
1390  LDA DATIN ;GET CHAR (Y=0)
1400  BCC I5 ;RETURN IF CHAR
1410  BPL I0 ;HORIZ WITH NO VERT
1420  AND #$7F ;CLEAR UPPER FLAG
1430  CMP #$51 ;TEST HORIZ/VERT
1440  BCC I00 ;HORIZONTAL
1450  AND #$1F ;CLEAR MID FLAG
1460  BCS I01 ;SAVE VERT
1470 I00 JSR I0 ;SAVE HORIZ
1480  BCC INPUT ;GET VERT
1490 I0 INY ;OFFSET FOR HORIZ
1500 I01 STA VCP,Y ;CURS POSITION
1510  STA VCS,Y ;CURS SHADOW
1520  CLC ;INDICATE RESPONSE
1530 I5 RTS
1540 ;
1550 CURCK LDA HCP ;CHECK HORIZ CURSOR
1560  CMP #$50 ;FOR >$4F
1570  BCC I5 ;IF NOT
1580  LDA #CUR80 ;GO GET REAL VALUE
1590  JSR CINP
1600  JMP I0 ;AND STORE IT (Y=0)
1610 ;
1620 CMD SEC ;THIS CODE MUST NOT
1630  BCS OUT ;CROSS A PAGE BOUNDARY
1640 OUTPUT CLC ;CMD FLAG=0 FOR CHAR
1650 OUT LDY #00
1660  JSR SEND ;SEND START BIT
1670  LDX #08 ;SETUP BIT COUNT OF 9
1680  NOP
1690  NOP
1700  NOP ;2+2+2+2=8
1710 OUT0 ROR A ;PUT BIT INTO CARRY
1720  BCS HI
1730  BCC LO ;2+3=5 CYCLES TO LO
1740 LO LDY #00 ;5+2 CYCLES TO JSR
1750  JSR SEND ;SEND A 0
1760  BCC OUT1 ;3 CYCLES
1770 HI LDY OUTMS ;3+4 CYCLES TO JSR
1780  JSR SEND ;SEND A 1
1790  BCS OUT1 ;3 CYCLES
1800 OUT1 DEX ;NEXT BIT 2 CYC
1810  BPL OUT0 ;MORE 3 OR 2 CYC
1820  BMI OUT2 ;SEND STOP BIT 3 CYC
1830 OUT2 LDY OUTMS ;SEND A 1
1840  BNE OUT3
1850 OUT3 JSR SEND ;2+3+4+3=12
1860  RTS
1870 SEND STY PORTA ;OUTPUT BIT
1880  LDY #12 ;TIMER FOR 15.7KB
1890 S1 DEY
1900  BNE S1 ;5*Y-1 CYCLES
1910  BEQ S2 ;3
1920 S2 NOP
1930  NOP
1940  NOP
1950  NOP ;2+2+2+2=8
1960 S3 RTS ;6 CYCLES
1970 ;
1980 COM LDA ICCOMZ ;GET COM BYTE
1990  CMP #$14 ;CHECK DEBUG OUT
2000  BNE COM1 ;TRY NEXT XIO
2010  LDA ICAX2Z ;GET AUX 2
2020 COMSD JSR DISAB ;STOP INTERRUPTS
2030  JSR CMD ;GO SEND
2040  JMP ENAB ;ENABLE AND NORM EXIT
2050 COM1 CMP #$15 ;TEST VALID
2060  BNE COM2 ;NEXT
2070  LDA ICAX2Z ;GET AUX 2
2080  BNE COMBR ;GO DO BURST
2090  STA MODE ;MAKE NORMAL
2100  LDA #SCR80 ;GET CMD
2110  BNE COMSD ;GO SEND
2120 COMBR STA MODE ;MAKE BURST
2130  LDA #SCB80 ;GET CMD
2140  BNE COMSD ;GO SEND
2150 COM2 CMP #$16 ;CHECK DEBUG IN
2160  BNE COM3 ;NEXT
2170  LDA ICAX2Z ;GET BYTE TO SEND
2180  JSR DISAB
2190  JSR CINP ;REQUEST, GET CHAR
2200  STA DVSTAT+1 ;FOR NOW
2210  JMP ENAB
2220 COM3 CMP #$19 ;CHECK 80/40
2230  BNE COM4
2240  JMP XIO19 ;DO IT
2250 COM4 RTS
2260 ;
2270 PCOM LDA ICCOMZ ;GET CMD
2280  CMP #$17 ;TEST VALID
2290  BNE S3 ;NO MORE FOR NOW
2300  LDA ICAX2Z ;GET AUX 2
2310  CMP #08 ;CHECK RESERVED
2320  BCS S3 ;NO GOOD
2330  AND #03 ;CHECK 3 AND 7
2340  EOR #03
2350  BEQ S3 ;NOT ALLOWED
2360  LDA ICAX1Z ;GET AUX1
2370  CMP #08 ;CHECK UPPER LIMIT
2380  BCS S3 ;NO GOOD
2390  STA PAUX1
2400  LDA ICAX2Z ;GET AUX 2
2410  STA PAUX2
2420  JMP EXIT
2430 ;
2440 WRITE LDY SFLAG ;CHECK CNTL 1
2450  BNE WRITE ;IF ON
2460  JSR DISAB
2470  LDY DEV ;ARE WE SCREEN?
2480  BEQ WR2 ;YES
2490  PHA
2500  LDA #00
2510  STA DEV
2520  LDA #SCR80
2530  JSR CMD
2540  PLA
2550 WR2 LDY LISTF ;CHECK LIST FLAG
2560  CPY LISTS
2570  BEQ WR3
2580  STY LISTS ;SAVE NEW VALUE
2590  PHA
2600  TYA
2610  BEQ WR25
2620  LDA #01 ;FORCE LSB
2630 WR25 ORA #LIS80
2640  JSR CMD ;SEND NEW VALUE
2650  PLA
2660 WR3 JSR ALIGN ;SET PARMS
2670  LDY CHBAS ;CHECK CHAR SET
2680  CPY CHSH
2690  BEQ WR5
2700  CPY #$E0
2710  BNE WR4
2720  STY CHSH
2730  PHA
2740  LDA #GRF80
2750 WR35 JSR CMD
2760  PLA
2770  JMP WR5
2780 WR4 CPY #$CC
2790  BNE WR5
2800  STY CHSH
2810  PHA
2820  LDA #ICM80
2830  BNE WR35
2840 WR5 LDY CRSINH ;CHECK CURS FLAG
2850  CPY CRSS
2860  BEQ WR6
2870  STY CRSS
2880  PHA
2890  TYA
2900  BEQ WR55
2910  LDA #01
2920 WR55 EOR #CRS80 ;CURSOR ON/OFF
2930  JSR CMD
2940  PLA
2950 WR6 JSR OUTPUT ;SEND CHAR
2960  LDA MODE ;TEST FOR BURST
2970  BNE WWAT ;IF SO
2980  JSR INPUT ;GET NEW CURSOR
2990  JSR CURCK ;CHECK FOR X>$4F
3000  JMP ENAB
3010 WWAT JSR ENAB ;ENABLE INTS
3020  LDY #25 ;OR SUCH
3030  JSR S1
3040 WW1 LDA PORTA
3050  AND INMSK
3060  BEQ WW1
3070 WW2 LDY #01
3080  RTS
3090 ;
3100 POPEN STX TIOCB
3110  LDX ICDNOZ
3120  JSR MATRIX
3130  BCS HANDGO
3140  LDY SDMCTL
3150  BNE WW2
3160  LDA #PST80
3170  JSR DISAB
3180  JSR CINP ;REQUEST, GET CHAR
3190  BNE POP1
3200  LDA #139 ;NOBODY HOME
3210 POP1 JSR ENAB
3220  TAY
3230  RTS
3240 ;
3250 HANDGO LDA ICDNOZ
3260  STX ICDNOZ
3270  PHA
3280  LDA ICCOMZ
3290  AND #08
3300  TAX
3310  JSR HAND
3320  PLA
3330  STA ICDNOZ
3340  RTS
3350 ;
3360 PWRT TAY ;SAVE CHAR
3370  STX TIOCB
3380  LDA ICDNO,X
3390  TAX
3400  JSR MATRIX
3410  TYA
3420  BCC PWP
3430  STA TCHAR ;SAVE CHAR FOR CALL
3440  LDY TIOCB ;GET UNIT #
3450  LDA ICDNO,Y
3460  PHA ;SAVE UNIT #
3470  TXA ;GET NEW VALUE
3480  STA ICDNO,Y ;REPLACE WITH NEW
3490  STA ICDNOZ ;AND ZERO PAGE
3500  LDX #06
3510  JSR HAND ;GO PRINT
3520  PLA ;RESTORE UNIT #
3530  LDX TIOCB ;GET POINTER
3540  STA ICDNO,X ;RESTORE OLD
3550  STA ICDNOZ
3560  RTS
3570 PWP LDY DEV ;CHECK OUTPUT DEV
3580  BNE PW0
3590  PHA
3600  LDY SDMCTL
3610  BEQ PW2
3620 PW1 LDY VCOUNT
3630  CPY #129
3640  BNE PW1
3650 PW2 JSR DISAB
3660  LDA #PNT80
3670  STA DEV
3680  JSR CMD
3690  JSR ENAB
3700  PLA ;RESTORE CHAR
3710 PW0 TAY ;SAVE CHAR
3720  LDA PAUX2 ;GET CNTL
3730  ROR A ;CHECK NO XLATE
3740  TYA ;RESTORE CHAR
3750  BCS DOIT ;DONT XLATE
3760  CMP #EOL ;CHECK EOL
3770  BNE XLATE ;XLATE IF NOT
3780  LDA #CR ;REPLACE WITH CR
3790  JSR DOIT ;SEND
3800  LDA PAUX2 ;GET CNTL
3810  AND #04 ;CHECK NO APPEND
3820  BNE WGDS ;DONT APPEND
3830  LDA #LF ;GET LF
3840  BNE DOIT ;SEND
3850 XLATE LDA PAUX2 ;GET CNTL
3860  CMP #02 ;CHECK LIGHT XLATE
3870  TYA ;RESTORE CHAR
3880  BCC DOIT ;DONE WITH XLATE
3890  AND #$7F ;REMOVE MSB
3900  CMP #$20 ;CHECK ASCII CHAR
3910  BCS DOIT ;GO PRINT ASCII
3920  PHA ;SAVE CHAR
3930  LDA #CNTL ;GET "CNTL" CHAR
3940  JSR DOIT ;SEND
3950  PLA ;RESTORE CHAR
3960  ORA #$40 ;MAKE ALPHA
3970 DOIT LDY SDMCTL
3980  BEQ DO1
3990 DO0 LDY VCOUNT
4000  CPY #129
4010  BNE DO0
4020 DO1 JSR DISAB
4030  JSR OUTPUT
4040  JSR ENAB
4050 WAIT LDY #25 ;FOR NOW
4060  JSR S1
4070  LDY #02
4080 W0 LDX #255 ;FOR NOW
4090  STX CDTMV3 ;SETUP VBLANK COUNT
4100 W1 LDA PORTA
4110  AND INMSK
4120  BNE WGDS ;AVAILABLE
4130  LDA CDTMV3 ;CHECK COUNTDOWN
4140  BNE W1
4150  DEY
4160  BNE W0
4170 WTMO LDY #138 ;DO TIMEOUT
4180  BNE WRTS ;COULD DO BRKKEY ALSO
4190 WGDS LDY #01
4200 WRTS RTS
4210 ;
4220 MATRIX CPX #02
4230  BEQ PNEXT
4240  BCS POVER
4250  LDA PAUX1
4260  LSR A
4270 POVER RTS
4280 PNEXT LDA #03
4290  CMP PAUX1
4300  BCC POVER
4310  LDA PAUX1
4320  AND #02
4330  BEQ POVER
4340  DEX
4350  RTS
4360 ;
4370 HAND LDA $E431,X
4380  PHA
4390  LDA $E430,X
4400  PHA
4410  LDA TCHAR ;RESTORE CHAR
4420  LDX TIOCB ;GET IOCB POINTER
4430  RTS ;CALL PRINTER HANDLER
4440 ;
4450 FORCOM LDA ICCOMZ
4460  CMP #$18
4470  BEQ XIO18
4480  RTS
4490 ;
4500 CINIT LDA #00
4510  STA TOGGLE
4520  JSR JINIT
4530  LDA #$50
4540  LDY #02
4550  JSR FSET
4560  LDA #$53
4570  JSR FIND
4580  LDA HATABS+1,X
4590  STA TEMPSV
4600  LDA HATABS+2,X
4610  STA TEMPSV+1
4620  LDA #$45
4630  JSR FIND
4640  LDA HATABS+1,X
4650  STA IN
4660  LDA HATABS+2,X
4670  STA IN+1
4680  LDY #15
4690 C003 LDA (IN),Y
4700  STA TMTAB,Y
4710  DEY
4720  BPL C003
4730  LDA #FORCOM-1&$FF
4740  STA TMTAB+10
4750  LDA #FORCOM-1/256
4760  STA TMTAB+11
4770  LDA SKSTAT
4780  AND #08
4790  BEQ C004
4800 XIO18 LDA #$45
4810  LDY #00
4820  JSR FSET
4830  LDA #$53
4840  LDY #01
4850  JSR FSET
4860  LDA #WRITE-1&$FF
4870  STA $346
4880  LDA #WRITE-1/256
4890  STA $347
4900 EOPEN LDX #00
4910  JSR FESUB
4920  LDA ICAX1Z ;GET AUX 1
4930  AND #32 ;CHECK CLEAR BIT
4940  BNE C005 ;DONT DO RESET
4950  LDA #00
4960  LDX #06
4970 C0035 STA VCS,X
4980  DEX
4990  BPL C0035
5000  LDA #$E0
5010  STA CHSH
5020  LDA #$4F
5030  STA RMARGS
5040  STA COMPOS
5050  JSR DISAB
5060 IO00 LDA #RST80 ;RESET 80 COL
5070  JSR CINP ;REQUEST, GET CHAR
5080  BCC IO01 ;GOT IT
5090  JSR JTOGL ;SWITCH PORTS
5100  BNE IO00 ;DO IT AGAIN
5110 IO01 LDA PAL ;CHECK COMPUTER TYPE
5120  AND #$0E
5130  BNE IOP1
5140  LDA #PAL80
5150  JSR CMD ;SET 80 COL TO 50HZ
5160 IOP1 JMP ENAB
5170 ;
5180 XIO19 LDX #06
5190  JSR FESUB
5200  LDA #$53
5210  JSR FIND
5220  LDA TEMPSV
5230  STA HATABS+1,X
5240  LDA TEMPSV+1
5250  STA HATABS+2,X
5260  LDA TMTAB+6
5270  STA $346
5280  LDA TMTAB+7
5290  STA $347
5300 C004 LDA #$45
5310  LDY #03
5320  JSR FSET
5330  JMP EXIT
5340 C005 LDA #SCR80 ;IN CASE A PRINT
5350  JMP COMSD ;HAS OCCURED
5360 ;
5370 EDTAB .WORD EOPEN-1 ;OPEN
5380  .WORD EXIT-1 ;CLOSE
5390  .WORD EGET-1 ;GET LINE OF TEXT
5400  .WORD WRITE-1 ;PUT (NO CURS)
5410  .WORD EXIT-1 ;STATUS
5420  .WORD COM-1 ;SPECIAL (CMD OUT)
5430  JMP EXIT ;INIT
5440  .BYTE 0
5450 ;
5460 PRTAB .WORD POPEN-1 ;OPEN
5470  .WORD EXIT-1 ;CLOSE
5480  .WORD ERTS-1 ;GET
5490  .WORD PWRT-1 ;PUT
5500  .WORD POPEN-1 ;STATUS
5510  .WORD PCOM-1 ;SPECIAL
5520  JMP EXIT ;INIT
5530  .BYTE 0
5540 ;
5550 SCTAB .WORD SOPEN-1 ;OPEN
5560  .WORD EXIT-1 ;CLOSE
5570  .WORD SREAD-1 ;GET-LOCATE
5580  .WORD SWRIT-1 ;PUT-PLOT
5590  .WORD EXIT-1 ;STATUS
5600  .WORD ERTS-1 ;SPECIAL
5610 SCT1 JMP EXIT ;INIT
5620  .BYTE 0
5630 ;
5640 TMTAB .WORD EXIT-1,EXIT-1
5650  .WORD EXIT-1,EXIT-1
5660  .WORD EXIT-1,EXIT-1
5670  JMP EXIT
5680  .BYTE 0
5690 ;
5700 SOPEN LDA ICAX2Z
5710  AND #08
5720  BEQ SCT1
5730  LDA ICAX1Z
5740  AND #16
5750  BNE SCT1
5760  LDA #00 ;SEND 0
5770  JSR DISAB
5780  JSR OUTPUT
5790  JSR INPUT
5800  LDA #SGR80 ;SET GRAPHICS
5810  JSR CMD
5820  LDA PAL
5830  AND #$0E
5840  BNE SOP1
5850  LDA #PAG80
5860  JSR CMD
5870 SOP1 LDA #CLR80 ;FILL WITH 0 SENT
5880  JSR CINP ;REQUEST, GET CHAR
5890  LDA #01
5900  JMP COMBR
5910 ;
5920 SREAD JSR DISAB
5930  JSR ALIGN ;SET PARMS
5940  JSR READ ;GET CHAR
5950  CMP #EOL ;CHECK EOL
5960  BNE SCT1 ;RETURN NORMAL
5970  LDA #SPACE ;REPLACE WITH SPACE
5980  BNE SCT1 ;RETURN NORMAL
5990 ;
6000 SWRIT PHA ;SAVE CHAR
6010  LDA #ESC ;FORCE PRINT
6020  JSR WRITE
6030  PLA ;RESTORE CHAR
6040  JMP WRITE ;SEND IT
6050 ;
6060 EGET LDA COMPOS
6070  BEQ EBACK
6080  LDA HCP
6090  STA HCPS
6094  STA HCPE
6100 EG1 JSR KCALL ;GET KB BYTE
6110  CMP #EOL
6120  BEQ EGBAK
6130  JSR WRITE ;SEND TO 80 COL
6132  LDY HCP ;THIS CODE IS FOR
6134  CPY HCPE ;SPECIAL CASE LINES
6140  BCC EG1 ;DONT UPDATE IF LESS
6142  STY HCPE
6144  BCS EG1
6150 EGBAK STY KSTAT ;SAVE STATUS
6160  CPY #$80 ;CHECK STAT
6170  BCS EBA0 ;DO EOL IF EOF/BREAK
6180  JSR DISAB ;DISAB FOR CMD
6190  LDA #00
6200  STA COMPOS
6210  LDA MODE
6220  BEQ EG2
6230  LDA #00
6240  BEQ EG3
6250 EG2 LDA HCPS
6260 EG3 JSR CMD ;X CURS TO OLD VAL
6270  LDA #MCF80 ;Y CURS TO FIRST
6280  JSR CMD
6290 EBACK JSR READ ;GO GET A CHAR
6300  CMP #EOL
6310  BNE EGXT ;NOT DONE YET
6312  LDY HCP
6314  CPY HCPE ;CHECK RIGHTMOST
6315  BCS EBA0 ;CURSOR POSITION
6316  LDA #SPACE ;IF NOT THERE
6318  BNE EGXT ;THEN FAKE SPACE
6320 EBA0 STA COMPOS ;SET NON 0
6330  JSR WRITE
6340  LDA #EOL ;RETURN WITH EOL
6350 EGXT LDY KSTAT ;GET STATUS
6360  RTS
6370 ;
6380 KCALL LDA $E425
6390  PHA
6400  LDA $E424
6410  PHA
6420  RTS
6430 ;
6440 DISAB LDY #00
6450  STY NMIEN
6460  SEI
6470  RTS
6480 ;
6490 ENAB LDY #$C0
6500  STY NMIEN
6510  CLI
6520 EXIT LDY #01
6530 ERTS RTS
6540 ;
6550 VCS .BYTE 0
6560 HCS .BYTE 0
6570 DEV .BYTE 0
6580 LMARGS .BYTE 0
6590 LISTS .BYTE 0
6600 MODE .BYTE 0
6610 CRSS .BYTE 0
6620 ;
6630 CHSH .BYTE 0
6640 RMARGS .BYTE 0
6650 COMPOS .BYTE 0
6660 ;
6670 DATIN .BYTE 0
6680 HCPS .BYTE 0
6685 HCPE .BYTE 0
6690 KSTAT .BYTE 0
6700 INMSK .BYTE 0
6710 OUTMS .BYTE 0
6720 TOGGLE .BYTE 0
6730 TIOCB .BYTE 0
6740 TCHAR .BYTE 0
6750 ;
6760 TEMPSV .WORD 0
6770 ;
6780 INMST .BYTE 02,$20
6790 OUTMT .BYTE 01,$10
6800 ;
6810 FETAB .BYTE 0,0,0,$4F,24,3
6820  .BYTE 62,0,2,39,30,6
6830 ;
6840 LOOKUP .BYTE "ESP"
6850 LOWAD .BYTE EDTAB&$FF,SCTAB&$FF,PRTAB&$FF,TMTAB&$FF
6860 ;
6870 ALIGN LDY HCP ;GET HCURS
6880  CPY HCS ;COMPARE TO SHADOW
6890  BEQ A1 ;NO CHANGE
6900  STY HCS ;SAVE NEW VALUE
6910  PHA ;SAVE CHAR
6920  TYA
6930  CMP #$50
6940  BCC A00
6950  LSR A
6960  LSR A
6970  LSR A
6980  LSR A
6990  ORA #XCH80
7000  PHA
7010  TYA
7020  AND #$0F
7030  JSR CMD
7040  PLA
7050 A00 JSR CMD ;SEND NEW CURSOR
7060  PLA
7070 A1 LDY VCP ;GET VCURS
7080  CPY #25 ;CHECK UPPER LIMIT
7090  BCC A15
7100  LDY #24 ;STATUS LINE
7110 A15 CPY VCS ;COMPARE TO SHADOW
7120  BEQ A2 ;NO CHANGE
7130  STY VCS ;SAVE NEW VALUE
7140  PHA ;SAVE CHAR
7150  TYA
7160  ORA #YCR80 ;SET CMD BIT
7170  JSR CMD ;SEND NEW CURSOR
7180  PLA
7190 A2 LDY LMARGN
7200  CPY RMARGN
7210  BCC A24
7220  LDY #00
7230  STY LMARGN
7240 A24 CPY LMARGS
7250  BEQ A3
7260  STY LMARGS
7270  PHA
7280  TYA
7290  AND #$0F
7300  ORA #LMG80
7310  JSR CMD
7320  LDA LMARGN
7330  LSR A
7340  LSR A
7350  LSR A
7360  LSR A
7370  BEQ A25
7380  ORA #LMH80
7390  JSR CMD
7400 A25 PLA
7410 A3 LDY RMARGN
7420  CPY RMARGS
7430  BEQ A4
7440  STY RMARGS
7450  PHA
7460  TYA
7470  AND #$0F
7480  ORA #RMG80
7490  JSR CMD
7500  LDA RMARGN
7510  LSR A
7520  LSR A
7530  LSR A
7540  LSR A
7550  CMP #04
7560  BEQ A35
7570  ORA #RMH80
7580  JSR CMD
7590 A35 PLA
7600 A4 RTS
7610 ;
7620 FESUB LDA FETAB,X
7630  STA SDMCTL
7640  STA DMACTL
7650  LDA FETAB+1,X
7660  STA VCP
7670  LDA FETAB+2,X
7680  STA HCP
7690  STA LMARGN
7700  LDA FETAB+3,X
7710  STA RMARGN
7720  LDA FETAB+4,X
7730  STA KEYDEL
7740  LDA FETAB+5,X
7750  STA KEYREP
7760  RTS
7770 ;
7780 FIND LDX #00
7790 F1 CMP HATABS,X
7800  BEQ F2
7810  INX
7820  INX
7830  INX
7840  BNE F1
7850 ;
7860 FSET JSR FIND
7870 SET LDA LOWAD,Y
7880  STA HATABS+1,X
7890  LDA #EDTAB/256
7900  STA HATABS+2,X
7910 F2 RTS
7920 ;
7930 JTOGL LDA #01
7940  EOR TOGGLE
7950  STA TOGGLE
7960 JINIT LDX TOGGLE
7970  LDY INMST,X
7980  STY INMSK
7990  LDY OUTMT,X
8000  STY OUTMS
8010  LDA #$FF
8020  STA PORTA
8030  LDX #$38
8040  STX PACTL
8050  STY PORTA
8060  LDX #$3C
8070  STX PACTL
8080  RTS
8090 ;
8100 CEND=*
8110 ;
8120  .END

Relocator Source#

0100  .OPT NOEJECT
0110 DOSINI=$0C
0120 IN=$CC
0130 OUT=$CE
0140 OFFSET=$D0
0150 MEMTOP=$2E5
0160 CBEGIN=LENGTH+2
0170  *=$3000
0180 ENTER SEC
0190  LDA MEMTOP
0200  SBC LENGTH
0210  LDA MEMTOP+1
0220  SBC LENGTH+1
0230  STA OUT+1
0240  STA OFFSET
0250  TAY
0260  DEY
0270  STY MEMTOP+1
0280  LDY #$FF
0290  STY MEMTOP
0300  INY
0310  STY OUT
0320  LDX #00
0330  LDA #CBEGIN&$FF
0340  STA IN
0350  LDA #CBEGIN/256
0360  STA IN+1
0370  JSR MOVI
0380 HERE TAX
0390  BMI MORE
0400  JSR MOVI
0410  CLC
0420  ADC OFFSET
0430  LDX #00
0440  JSR MOV
0450  BMI HERE
0460 MORE INX
0470  BEQ OVER
0480  DEX
0490  JSR MOVI
0500  BMI HERE
0510 MOV STA (OUT),Y
0520  INC OUT
0530  BNE MOVI
0540  INC OUT+1
0550 MOVI LDA (IN),Y
0560  INC IN
0570  BNE MOVO
0580  INC IN+1
0590 MOVO DEX
0600  BPL MOV
0610 ARND RTS
0620 OVER LDA #01
0630  STA OUT
0640  LDA OFFSET
0650  STA OUT+1
0660  LDA DOSINI
0670  STA (OUT),Y
0680  INC OUT
0690  LDA DOSINI+1
0700  STA (OUT),Y
0710  INC OUT
0720  TYA
0730  STA DOSINI
0740  LDA OFFSET
0750  STA DOSINI+1
0760  JMP (OUT)
0770 LENGTH=*

BASIC Relocator#

10 REM RELOCATING PROGRAM FOR XEP80
20 REM TO USE THIS PROGRAM THE FOLLOWING CRITERIA MUST BE MET:
30 REM .  THE HANDLER SOURCE CODE MUST BE ASSEMBLED TWICE, THE FIRST
40 REM .  ASSEMBLY AT ANY CHOSEN START ADDRESS AND THE SECOND AT
50 REM .  THAT ADDRESS+$100. THE FIRST OBJECT CODE WILL BE CALLED
60 REM .  H6000.OBJ AND THE SECOND OBJECT CALLED H6100.OBJ. THE 
70 REM .  RELOCATER CODE MUST BE ASSEMBLED AS FILE MOVE.OBJ. THIS
80 REM .  PROGRAM WILL READ IN MOVE.OBJ THEN COMPARE BYTES BETWEEN
90 REM .  H6000.OBJ AND H6100.OBJ AND CREATE A LINKED RELOCATABLE
100 REM . STRING. THIS STRING IS APPENDED TO THE MOVE.OBJ STRING
105 REM . THEN WRITTEN TO DISK AS AUTORUN.SYS
110 CLR :DIM A$(2048)
120 DIM REL$(14),OB1$(14),OB2$(14),OUT$(14)
130 REL$="D:MOVE.OBJ"
131 OB1$="D:H6000.OBJ"
132 OB2$="D:H6100.OBJ"
133 OUT$="D:AUTORUN.SYS"
200 PULL=3000:REND=3500:WRITE=4000
205 ADD=5000
210 TREND=32768:IN=1
300 OPEN #1,4,0,REL$:FILE=1
310 TRAP REND:TEND=0
320 GOSUB PULL
322 IF TEND=1 THEN GOTO 340
324 A$(IN,IN)=CHR$(DAT)
325 GOSUB ADD
330 GOTO 320
340 CLOSE #1
350 TRAP TREND
400 OPEN #2,4,0,OB1$
410 OPEN #3,4,0,OB2$
415 TRAP REND:TEND=0
417 FOR X=0 TO 5:FILE=2:GOSUB PULL:FILE=3:GOSUB PULL:NEXT X
418 FOR X=0 TO 1:FILE=2:GOSUB PULL:FILE=3:GOSUB PULL
419   A$(IN,IN)=CHR$(DAT):GOSUB ADD:NEXT X
420 COUNT=0
430 SPOT=IN
440 GOSUB ADD
445 IF COUNT>127 THEN GOTO 487
450 FILE=2:GOSUB PULL:IF TEND=1 THEN GOTO 550
455 T1=DAT
460 FILE=3:GOSUB PULL:T2=DAT
470 IF T1<>T2 THEN GOTO 500
480 A$(IN,IN)=CHR$(T1):COUNT=COUNT+1
485 GOTO 440
487 A$(SPOT,SPOT)=CHR$(128)
490 GOTO 420
500 A$(SPOT,SPOT)=CHR$(COUNT)
510 TR=T1-96:REM SHOULD READ FROM FILE
520 A$(IN,IN)=CHR$(TR)
530 GOSUB ADD
540 GOTO 420
550 A$(SPOT,SPOT)=CHR$(COUNT)
551 A$(IN,IN)=CHR$(0)
552 GOSUB ADD
553 A$(IN,IN)=CHR$(255)
554 CLOSE #2:CLOSE #3
560 START=ASC(A$(3,3))+ASC(A$(4,4))*256
570 FEND=START+IN-7
580 HI=INT(FEND/256):LO=FEND-HI*256
590 A$(5,5)=CHR$(LO):A$(6,6)=CHR$(HI)
591 GOSUB ADD:A$(IN,IN+6)=""
600 REM STOP
700 OPEN #4,8,0,OUT$
710 ? #4;A$;
720 CLOSE #4
800 STOP 
900 REM THIS SECTION CAN BE ENABLED TO OUTPUT A HEX VERSION OF THE FILE
1000 DIM T$(16):T$="0123456789ABCDEF"
1002 FOR X=0 TO LEN(A$)-1
1003   M=INT(X/256):MH=X-M*256:H=INT(MH/16):L=MH-H*16:M=M+1:H=H+1:L=L+1
1004   ? T$(M,M);T$(H,H);T$(L,L);"  ";
1010   R=ASC(A$(X+1,X+1))
1020   H=INT(R/16):L=R-H*16:H=H+1:L=L+1
1030   ? T$(H,H);T$(L,L)
1040 NEXT X
1050 STOP 
3000 GET #FILE,DAT
3010 RETURN 
3500 TEND=1:RETURN 

Diagrams#

Atari XEP80 diagram 1 ; thank you so much Jerzy Sobola for your help! Greatly appreciated!

Atari XEP80 diagram 2

References#

XEP 80 Demos in Basic#

Attributes Example#

100 REM ATTRIBUTES EXAMPLE
110 REM TO SET ATTRIBUTES USE FOLLOWING DEFINITIONS TO FORM COMMAND
120 REM .   THE XEP80 CONTAINS TWO ATTRIBUTE REGISTERS 
130 REM .  REGISTER A IS USED WHEN A CHARACTER ASCII VALUE IS BELOW 128
140 REM .  REGISTER B IS USED WHEN A CHARACTER ASCII VALUE IS ABOVE 127
150 REM .  EACH REGISTER REMAINS CONSTANT ACROSS THE SCREEN
160 REM .  THAT IS, NO MATTER WHERE A CHARACTER IS PLACED ON THE SCREEN
170 REM .  ITS ATTRIBUTES WILL REMAIN THE SAME                     
180 REM .   REGISTER BIT DEFINITIONS:
190 REM .     BIT     EFFECT IF A 0
200 REM .      0      REVERSE VIDEO
210 REM .      1      NO EFFECT
220 REM .      2      BLINKING
230 REM .      3      NO EFFECT  
240 REM .      4      DOUBLE WIDE
250 REM .      5      UNDERLINE
260 REM .      6      BLANK
270 REM .      7      SPECIAL TEXT GRAPHICS
280 REM .   TO ISSUE A COMMAND DO THE FOLLOWING:
290 REM .   1)  PRINT CHR$(27);
300 REM .   2)  PRINT CHR$(VALUE DERIVED FROM ABOVE BIT DEFINITIONS);
310 REM .   3)  XIO 20,#1,12,A,"E:"
320 REM .       WHERE A=244 FOR REGISTER A AND A=245 FOR REGISTER B
330 REM .   THEN PRINT CHARACTERS ON THE SCREEN, EITHER WITH BIT 7 OFF
340 REM .   TO USE REGISTER A, OR WITH BIT 7 ON TO USE REGISTER B
400 ? "}";:POSITION 28,11:? "E X A M P L E   T E X T ":POKE 752,1
410 GOSUB 2000
500 REM SOME ATTRIBUTE COMBINATIONS
510 ? CHR$(27);CHR$(255-1);:XIO 20,#1,12,245,"E:"
520 ? CHR$(27);CHR$(255-1);:XIO 20,#1,12,245,"E:"
530 GOSUB 2000:REM REVERSE VIDEO   
550 ? CHR$(27);CHR$(255-4);:XIO 20,#1,12,244,"E:"
560 ? CHR$(27);CHR$(255-1);:XIO 20,#1,12,245,"E:"
580 GOSUB 2000:REM BLINKING
600 ? CHR$(27);CHR$(255-16);:XIO 20,#1,12,244,"E:"
610 ? CHR$(27);CHR$(255-1);:XIO 20,#1,12,245,"E:"
630 GOSUB 2000:REM SOME DOUDLE WIDE
700 ? CHR$(27);CHR$(255);:XIO 20,#1,12,244,"E:"
710 ? CHR$(27);CHR$(255-16-1);:XIO 20,#1,12,245,"E:"
730 GOSUB 2000:REM OTHERS DOUBLE WIDE
750 ? CHR$(27);CHR$(255-16);:XIO 20,#1,12,244,"E:"
760 ? CHR$(27);CHR$(255-16-1);:XIO 20,#1,12,245,"E:"
780 GOSUB 2000:REM ALL DOUBLE WIDE
800 ? CHR$(27);CHR$(255-128);:XIO 20,#1,12,244,"E:"
810 ? CHR$(27);CHR$(255-128-1);:XIO 20,#1,12,245,"E:"
830 GOSUB 2000:REM ALL GRAPHICS
850 ? CHR$(27);CHR$(255);:XIO 20,#1,12,244,"E:"
860 ? CHR$(27);CHR$(255);:XIO 20,#1,12,245,"E:"
880 GOSUB 2000:REM BACK TO NORMAL
990 POKE 752,0:END 
2000 ? "~~";:FOR X=0 TO 999:NEXT X:RETURN 

Scrolling Window Example#

100 REM SCROLLING WINDOW EXAMPLE
105 REM SCROLL LEFT AND RIGHT WITH JOYSTICK, WHEN FINISHED PRESS TRIGGER
107 POKE 53774,64:REM DISABLE BREAK KEY
110 POKE 83,255:POKE 752,1:REM SET RIGHT MARGIN, CURSOR OFF
112 FOR COL=0 TO 3*57 STEP 57:GOSUB 1050:REM CLEAR ALL WINDOWS
114   ? CHR$(125);:NEXT COL:COL=0:GOSUB 1050:REM SET FIRST WINDOW
120 ? CHR$(125);:POSITION 0,20:? "USE JOYSTICK TO SCROLL",,,
125 ? "PRESS TRIGGER BUTTON TO EXIT"
130 FOR X=0 TO 15:POSITION X*16,1:? "COLUMN ";X;
140   GOSUB 1000:FOR Y=3 TO 16:REM ALLOW SCROLLING
150     POSITION X*16+2,Y:? INT(RND(0)*100);:REM MAKE UP A VALUE
160     GOSUB 1000:REM ALLOW SCROLLING WHILE PRINTING
170   NEXT Y:NEXT X
180 GOSUB 1000:GOTO 190-STRIG(1)*10:REM ALLOW SCROLLING, CHECK TRIGGER
190 POSITION 0,20:? CHR$(253);:XIO 20,#1,12,220,"E:":POKE 83,79:POKE 752,0
195 POKE 53774,192:REM ENABLE BREAK KEY
200 END :REM WINDOW TO LEFT EDGE, RESET RIGHT MARGIN, CURSOR ON, EXIT
1000 REM JOYSTICK ROUTINE
1010 A=STICK(1):COL=COL+SGN((A=7)-(A=11)):REM GET DIRECTION AND MOVE
1030 COL=COL*(COL>-1 AND COL<177)+(COL=177)*176:REM LIMITS OF SCROLLING
1050 POSITION COL,20:? CHR$(253);:XIO 20,#1,12,220,"E:"
1060 REM LINE 1050 SETS THE NEW CURSOR AND ISSUES THE SCROLL COMMAND
1090 RETURN 

Graphics Example (Circle)#

0 GOTO 100:REM KEEP TIME DEPENDENT CODE NEAR BEGINNING
10 FOR M=0 TO 12:V=0:S=128:FOR N=0 TO 7:X=P+N:REM LOOPS FOR CIRCLE LIMITS
20     V=V+S*(X*X+Y*Y*2.3<2500):S=S/2:NEXT N:P=P+8:REM CIRCLE CALCULATION
30   IF V THEN G$(M+1,M+1)=CHR$(V):REM SET BITS FOR OUTPUT STRING
40 NEXT M:? G$;:GOTO 170:REM PRINT OUTPUT STRING
100 REM GRAPHICS DISPLAY EXAMPLE TO DRAW CIRCLE
110 POKE 752,1:? CHR$(125);:DIM G$(40),D$(40):REM CURSOR OFF       
111 ? :? "  PRESS ANY KEY TO BEGIN GRAPHICS PLOTTING (TOTAL TIME 5 MIN)"
112 ? :? "  WHEN PLOT IS FINISHED PRESS ANY KEY TO RETURN TO TEXT SCREEN"
113 IF PEEK(764)=255 THEN 113
114 POKE 764,255:REM RESET CHARACTER INPUT BYTE
115 D$=CHR$(0):D$(40)=CHR$(0):D$(2)=D$:GRAPHICS 8+16:REM INIT STRING  
117 POKE 53774,64:REM DISABLE BREAK KEY
120 FOR Y=-32 TO 32:REM VERTICAL AXIS LOOP
130   G$=D$:P=-50:GOTO 10:REM GO TO TIME CRITICAL CODE
170 NEXT Y
180 IF PEEK(764)=255 THEN 180:REM HOLD SCREEN
185 POKE 53774,192:REM ENABLE BREAK KEY
190 POKE 764,255:OPEN #1,12,0,"E:":POKE 752,0:END :REM RESTORE TEXT SCREEN

Printer Configuration Program#

100 REM PRINTER CONFIGURATION PROGRAM
110 DIM A$(2048),IN$(16),OUT$(16):REM ALLOCATE STRINGS
120 IN$="D:AUTORUN.SYS":REM READ THIS FILE
130 OUT$="D:PRINT.SYS":REM CREATE THIS FILE
140 TRAP 32000:REM IF NO AUTORUN.SYS
150 OPEN #1,4,0,IN$
160 TRAP 180:REM TO CATCH EOF
170 A=A+1:GET #1,B:A$(A,A)=CHR$(B):GOTO 170:REM BUILD INPUT STRING
180 CLOSE #1
190 I=136:? "AUX1 VALUE";:INPUT A:REM PRINTER AUX1 BYTE
200 A$(I,I)=CHR$(A)
210 I=137:? "AUX2 VALUE";:INPUT A:REM PRINTER AUX2 BYTE
220 A$(I,I)=CHR$(A)
230 OPEN #2,8,0,OUT$
240 ? #1;A$;:CLOSE #2:REM WRITE MODIFIED STRING TO FILE
250 END 
32000 ? "FILE NOT FOUND"