summaryrefslogtreecommitdiffstats
path: root/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/Microbase
diff options
context:
space:
mode:
Diffstat (limited to 'docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/Microbase')
-rw-r--r--docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/Microbase1682
1 files changed, 1682 insertions, 0 deletions
diff --git a/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/Microbase b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/Microbase
new file mode 100644
index 0000000..3251a42
--- /dev/null
+++ b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/Microbase
@@ -0,0 +1,1682 @@
+BBC MICROBASE SERIES
+BBC 6502 Machine Code by Geoff Cox
+----------------------------------
+This series was first published on Micronet
+between April and October 1991
+
+The BBC Micro Operating System
+Part One: The moving electron writes
+------------------------------------
+In the last series we reviewed the basics of machine code programming
+using the 6502. You will have noticed that not too many examples of
+programming were given. This is because there are two levels of
+programming on any machine, machine level and operating system level.
+
+Operating Systems
+-----------------
+An operating system is basically a group of routines that sit between
+the user and the electronics of the computer. To illustrate what an
+operating system does we have to turn briefly from the path of the
+series.
+
+We'll imagine that you want to write the letter A on the screen of
+your monitor. First we have to work out the shape of the character and
+slice it horizontally into eight sections, one for each of eight
+screen scanning lines on the monitor.
+
+Now we need to detect when the frame synchronising pulse for the
+monitor is sent by the computer. Next we need to count the line
+synchronising pulses to find the one corresponding to the start of the
+first line of the character.
+
+Then we must time from this pulse to the start of the first line of
+the character, turn on the appropriate electron guns in the monitor
+and turn them off at the correct time for the end of the of the
+character. Finally we have a few microseconds to do it all again for
+the next line. That's more or less what happens fifty times a second
+on your monitor screen.
+
+Mapped Screens
+--------------
+This makes even the easiest task very complex. We can make life easier
+by storing a picture or map of the screen in memory and writing the
+character shape to the appropriate map locations.
+
+The map can then be scanned in synchronisation with the electron beam
+on the monitor. This can either be via a clever piece of electronics
+or a software routine.
+
+To illustrate the BBC map, type the following program on any 6502-
+based BBC without screen RAM shadowing.
+
+10 MODE 0
+20 ?&7D00=65
+
+You should see two little white dots towards the bottom right of the
+screen. Now two dots are not the letter A so if we want to write A we
+have to designthe character and write it to the map. This program does
+just that.
+
+10 MODE 0
+20 FOR A=&7D00 TO &7D07
+30 READ B
+40 ?A=B
+50 NEXT
+60 DATA &3C, &66, &66, &7E
+70 DATA &66, &66, &66, &00
+
+The sharp-eyed among you will have spotted something a little odd
+here. The screen seems to be arranged in blocks of eight bytes in this
+mode. Don't worry about this - it simply makes character table design
+simpler.
+
+Character Tables
+----------------
+We can make life even easier by designing a set of characters and
+putting them in an area of memory where they can be looked up. In the
+BBC B this area is in ROM starting at &C000.
+
+A quick diversion here. If we have to have a series of character
+designs in memory it helps to have a standard method of accessing
+them.
+
+The standard character ordering is called ASCII. A space has ASCII
+number 32 and this is the first "printable" character in the set. The
+last is 127 (Delete). There are eight bytes in each character matrix
+so the design for any character is at &C000+(8*(ASCII - 32)).
+
+This program examines the ROM character table and shows how characters
+are arranged.
+
+10 MODE 0
+20 PRINT "CHARACTER ?"
+30 A$=GET$
+40 PRINT A$
+50 START=(8(ASC(A$)-32))+&C000
+60 FIN=START+7
+70 FOR BYTE=START TO FIN
+80 PEEK=?BYTE
+90 PROC_BIN
+100 PRINT~BYTE;TAB(15);~?BYTE;TAB(20);
+110 NEXT
+120 END
+130 DEFPROC_BIN
+140 A$=""
+150 FOR BIT=7 TO 0 STEP-1
+160 X=(PEEK AND 2^BIT)
+170 IF X>1 THEN A$=A$+"" ELSE A$=A$+"."
+180 NEXT
+190 ENDPROC
+
+As you will often want to write characters on the screen it makes a
+lot of sense to have a little routine to take a character from a
+register and print it on the screen.
+
+The routine will look up a character in the table and print it to the
+appropriate position on the screen. There will also need to be a
+record of the cursor position on the screen.
+
+Routines for printing and moving a cursor on the screen will also be
+useful. You could, of course, write all of these routines yourself as
+part of every program but as the computer manufacturer has to provide
+them in order to tell you the machine is working he usually leaves an
+access point for you to use the routines yourself.
+
+Incidentally if you rewrite the first program but change line 10 to
+read MODE 7 you will see a letter A on the screen.
+
+This is an example of clever electronics. A chip on the BBC board
+contains a character generator. Instead of the character design being
+stored in the screen map the character's ASCII value is stored. This
+is read by the electronics and used to generate characters directly on
+the screen. This allows a 40 x 80 text and block graphics screen to be
+generated in just 1K of RAM.
+
+Using the Operating System
+--------------------------
+The screen handling routines and several others make up an operating
+system. In the BBC micro the series of routines that write a character
+on the screen can be accessed though a point called OSWRCH at &FFFE.
+
+So instead of having to design characters, time lines and do all of
+the other things, you can output a letter A to the screen simply
+using:
+
+LDA #65
+JSR &FFEE ;OSWRCH
+
+and leave the operating system to do the rest.
+
+
+BBC 6502 Machine Code
+Part Two: In the beginning
+--------------------------
+Last week we looked at the reasons for an operating system and how it
+can simplify the programmer's task. Unfortunately you will not always
+be able to use the operating system. There may not be a suitable
+routine or it may be too slow. In these cases you have to write to the
+device itself. So to continue our look at machine code we need to
+examine programming with device handling and the operating system.
+
+This series will attempt to kill two birds with one stone by taking
+avery close look at Acorn's OS 1.20 used on Model Bs.
+
+This changed little for the B+ and Master so while the routines may be
+in a slightly different place the basic system will be the same. The
+Master uses 65C02 code which has a few extra instructions so there may
+be some differences in the length of the code.
+
+What you will need
+------------------
+A disassembler or machine code monitor that can handle 6502 or 65C02
+codes. If If you don't have either you can use:
+
+PRINT ~?address
+
+to get the hexadecimal codes which you can then look up in the back of
+the BBC User Guide to get the relevant command.
+
+Suitable Monitors are EXMON, BBC Monitor or the SYSTEM monitor. (I use
+"Maxim" - Ed.) If you have a single- stepping monitor like one of
+these, you will be able to trace some of the routines for yourself.
+
+For this series we will use standard 6502 mnemonics except that DB and
+DW will be used to show byte assignments rather than EQUS, EQUW and
+EQUB. This is because the disassembler I am using produces these codes
+and it's a lot easier to follow than convoluted BBC-type statements.
+
+First things first
+------------------
+Remember that an operating system is not a program in the usual sense.
+Normal programs have a defined entry and exit routines. An operating
+system can have a large number of entry and exit points as well as
+interlocking routines. So to examine the operating system we need a
+starting point.
+
+The 6502 regards memory as a series of 256-byte pages 0 to &FF (255).
+Any address can be considered to be a page number plus an offset
+within the page. Both figures can be represented by a single byte. So
+address &FF01 is on Page &FF offset 01. The concept of offsets is very
+useful if you ever get involved in 80n86 programming.
+
+The BBC Manual gives a series of system entry points on page FF. Most
+of these are indirected through Page 2 and as we cannot guarantee what
+the contents of Page 2 should be (the vectors can be and are changed)
+these are useless as starting points. This leaves three sensible entry
+points.
+
+6502 Vectors
+FFFA DW &0D00 ;NMI address
+FFFC DW &D9CD ;RESET address
+FFFE DW &DC1C ;IRQ address
+
+The NMI address is in RAM so no joy there, but the other two look
+fine. The best is RESET as this is where the machine starts when it is
+turned on or BREAK is pressed. In the case of Model B and OS 1.20 that
+address is &D9CD, so what happens?
+
+In the beginning
+----------------
+Reset can be effected by turning on the computer or pressing BREAK. If
+it is a power-up then the system VIA and processor are reset
+electronically.
+
+If this is a power on situation then nothing has been set up. The
+first thing that happens when power is turned on is that the 6522
+VIAs, the processor and the floppy disc controller are reset. This is
+done by means of one of three printed circuit tracks. The tracks are
+RSTA, RST and NOTRESET.
+
+RSTA is only connected to the system 6522 Versatile Interface adaptor
+(VIA). This operates through a little resistor/capacitor circuit that
+only works when the power is turned on. The effect of this is that the
+6522 System VIA Interrupt Enable Register (IER) bits 0 to 6 will be
+clear (0) only if the reset is caused by a power on condition.
+
+If the Reset is caused by BREAK being pressed then the machine must
+have been on and therefore one or more of the System VIA IER bits will
+be set (to 1). If one or more bits are set then bit 7 of the VIA will
+also be set. This is used to determine the type of Reset. So let's
+look at the operating system more closely.
+
+D9CD LDA #&40 ;set NMI first instruction to RTI
+D9CF STA &0D00 ;NMI RAM start
+
+RESET is the ultimate Act of God as far as the machine is concerned.
+Anything could be happening so the operating system has to clean up
+the system as its first act.
+
+These first instructions just make sure that if a disc is running no
+more information will be read or written from or to the disc. This
+illustrates why you shouldn't press BREAK when a disc is being
+accessed!
+
+The next section sets up the stack:
+
++
+D9D2 SEI ;disable interrupts just in case
+D9D3 CLD ;clear decimal flag
+D9D4 LDX #&FF ;reset stack to where it should be
+D9D6 TXS ;(&1FF)
+
+Next find out if a power-up reset or a BREAK press by examining the
+System VIA IER register.
+
+D9D7 LDA &FE4E ;read interrupt enable register of the system VIA
+D9DA ASL ;shift bit 7 into carry
+D9DB PHA ;save what's left
+D9DC BEQ &D9E7 ;if Power up A=0 so go to D9E7 to clear memory
+
+That's probably enough for this time. Don't worry! I don't intend to
+do a complete disassembly of the operating system in this series but
+we will follow through the power-on sequence to the end because a lot
+of interesting things happen at this time.
+
+We'll take a look at D9E7 and the next routine in this sequence (D9DE)
+in the next part.
+
+
+BBC 6502 Machine Code
+Part Three: Cleaning up the mess
+--------------------------------
+In the last part we looked at what happens when you press BREAK or
+switch on the machine. We'll now continue with a look at an
+undocumented (at least officially) routine.
+
+The byte at &258 can be used to contain information about what the
+machine should do if BREAK is pressed. FX200,n is used to set this
+byte. If n=2 or n=3 then the memory must be cleared. This is often
+used in program protection.
+
+D9DE LDA &0258 ;else if BREAK pressed read BREAK Action flags (set by FX200,n)
+D9E1 LSR ;divide by 2
+D9E2 CMP #&01 ;if &0258 <> 2 or 3
+D9E4 BNE &DA03 ;then Goto &DA03
+D9E6 LSR ;divide A by 2 again (A=0 if FX200,2/3 else A=n/4
+
+Pages 4-&7F are cleared by a simple loop if &258=2 or 3 or it is a
+power on reset. Look out for the clever way of avoiding problems on
+16K machines.
+
+D9E7 LDX #&04 ;get page to start clearance from (4)
+D9E9 STX &01 ;store it in ZP 01
+D9EB STA &00 ;store A at 00
+D9ED TAY ;and in Y to set loop counter
+ ;LOOP STARTS
+D9EE STA (&00),Y ;clear RAM
+D9F0 CMP &01 ;until page address (in &01) =0
+D9F2 BEQ &D9FD ;
+D9F4 INY ;increment pointer
+D9F5 BNE &D9EE ;if not zero loop round again
+D9F7 INY ;else increment again (Y=1) this avoids overwriting the RTI
+ ;instruction at &D00
+D9F8 INX ;increment X
+D9F9 INC &01 ;increment &01
+D9FB BPL &D9EE ;loop until Page (in 01)=&80 then exit
+
+Note that RAM addressing for 16K loops around to &4000=&00 hence the
+checking of &01 for 00. This avoids overwriting zero page on BREAK
+which would cause the machine to crash!
+
+D9FD STX &028E ;writes marker for available RAM 40 =16K,80=32
+DA00 STX &0284 ;write soft key consistency flag
+
+This routine shows the basic structure of a loop. Those of you who
+program in BASIC will recognise it as a very simple structure:
+
+10 A=A+1
+20 IF A<20 GOTO 10
+
+The loop uses zero page addressing with the target address in 00 and
+01 (Page) and the index in Y.
+
+The loop is exited when the value in 01 becomes negative. Remember
+that all values between 0 and &7F are considered to be positive, so
+the BPL instruction can be used to exit the loop at page &80, the
+first negative number. This is the first of the useful loop techniques
+we'll see in this series.
+
+Notice that the first byte of each page is left unchanged. This is
+useful if you want information to survive a BREAK of this type. This
+clearing of memory is not normally carried out.
+
+Next week we'll have a look at the normal RESET path.
+
+BBC 6502 Machine Code
+Part Four: Cleaning up even more mess
+-------------------------------------
+As we saw last week, a normal warm reset avoids the memory clearance
+and proceeds to set up the System VIA.
+
+DA03 LDX #&0F ;set PORT B data direction register to output on bits
+ ;0-3 and input bits 4-7
+DA05 STX &FE42 ;
+
+The next bit is a little more complicated and is intimately bound up
+with hardware. The function is to set up the addressable latch IC 32
+for peripherals via PORT B.
+
+The latch value is written by writing the value to &FE40 bits 0 to 2
+and either a 1 or 0 to bit 3.
+
+Writing the value + 8 therefore writes a 1 to the latched address,
+otherwise a 0 is written.
+
+Value Peripheral Effect
++ 0 8
+
+0 Sound chip Enabled Disabled
+ Speech Chip
+1 (RS) Low High
+2 (WS) Low High
+2 (WS) Low High
+3 Keyboard
+ Write Disabled Enabled
+4 C0 address
+ modifier Low High
+5 C1 address
+ modifier Low High
+6 Caps LED On Off
+7 Shift LED On Off
+
+C0 and C1 are involved with hardware scroll screen address.
+
+ ;X=&F on entry
+DA08 DEX ;loop start
+DA09 STX &FE40 ;Write latch IC32
+DA0C CPX #&09 ;Is it 9?
+DA0E BCS &DA08 ;If not go back and do it again
+ ;X=8 at this point
+ ;Caps Lock On, SHIFT Lock undetermined
+ ;Keyboard Autoscan on
+ ;Sound disabled (may still sound)
+
+Next the keyboard is scanned to determine the values of the keyboard
+links and whether a Ctrl-Break has been performed.
+
+Remember that although we have spent a lot of time reading this, we
+are probably less than 200 microseconds after BREAK was pressed.
+
+The check for Ctrl-Break is effectively looking for simultaneous
+keypresses.
+
+DA10 INX ;X=9
+DA11 TXA ;A=X
+DA12 JSR &F02A ;Interrogate keyboard
+DA15 CPX #&80 ;for keyboard links 9-2 and CTRL key (1)
+DA17 ROR &FC ;rotate MSB into bit 7 of &FC
+
+DA19 TAX ;Get back value of X for loop
+DA1A DEX ;Decrement it
+DA1B BNE &DA11 ;and if >0 do loop again
+ ;On exit if Carry set link 3 is made
+ ;link 2 = bit 0 of &FC and so on
+ ;If CTRL pressed bit 7 of &FC=1 X=0
+DA1D STX &028D ;Clear last BREAK flag
+DA20 ROL &FC ;CTRL is now in carry &FC is keyboard links
+DA22 JSR &EEEB ;Set LEDs
+ ;Carry set on entry is in bit 7 of A on exit
+DA25 ROR ;Get carry back into carry flag
+
+To review what the operating system has done so far, about 400
+microseconds after a BREAK press or about 2 milliseconds from a power
+on. Memory may have been cleared, NMIs have been short circuited, IRQs
+disabled. The keyboard has been scanned for made links and for Ctrl
+being pressed.
+
+We have also located two important and undocumented subroutines: &F02A
+to scan the keyboard and &EEEB to set the keyboard LEDs.
+
+The F02A routine scans for the key whose code is in X being pressed:
+
+F02A LDY #&03 ;Stop Auto scan
+F02C STY &FE40 ;by writing to system VIA
+F02F LDY #&7F ;Set bits 0 to 6 of port A to input on bit 7.
+ ;Output on bits 0 to 6
+F031 STY &FE43 ;
+F034 STX &FE4F ;Write X to Port A system VIA (key to check)
+F037 LDX &FE4F ;Read back &80 if key pressed (M set)
+F03A RTS ;And return
+
+The routine at &EEEB switches on the selected keyboard lights.
+
+EEEB PHP ;Save flags
+EEEC LDA &025A ;Read keyboard status
+ ;Bit 7=1 shift enabled
+ ;Bit 6=1 control pressed
+ ;Bit 5 =0 shift lock
+ ;Bit 4 =0 Caps lock
+ ;Bit 3 =1 shift pressed
+EEEF LSR ;Shift Caps bit into bit 3
+EEF0 AND #&18 ;Mask out all but 4 and 3
+EEF2 ORA #&06 ;Returns 6 if caps lock OFF &E if on.
+ ;Remember add 8 to the value for the addressable
+ ;latch to send a 1.
+EEF4 STA &FE40 ;Turn on or off caps light if required
+EEF7 LSR ;Bring shift bit into bit 3
+EEF8 ORA #&07 ;
+EEFA STA &FE40 ;Turn on or off shift lock light
+EEFD JSR &F12E ;Set keyboard counter
+EF00 PLA ;Get back flags into A
+EF01 RTS ;Return
+
+In this part we've had a look at subroutines using JSR and RTS, the
+machine code equivalent of GOSUB, PROC or FN. Subroutines are often
+used in machine code to perform such frequently needed functions as
+scanning a keyboard or turning on and off lights.
+
+We've also discovered that the byte at &25A contains the keyboard
+status. Try changing it for yourself. You can therefore use OR and AND
+to set the shift and Caps lock status of the machine for a particular
+program.
+
+Next week we'll examine setting up the default vector table in memory.
+
+BBC 6502 Machine Code
+Part Five: Vectors Victor
+-------------------------
+The next stage is to set up the vectors on page 2.
+
+DA26 LDX #&9C ;
+DA28 LDY #&8D ;
+DA2A PLA ;Get back A from &D9DB
+DA2B BEQ &DA36 ;If A=0 power up reset so go to DA36 with X=&9C
+ ;Y=&8D
+DA2D LDY #&7E ;else let Y=&7E
+DA2F BCC &DA42 ;and if not CTRL- BREAK go to DA42 for a WARM RESET
+DA31 LDY #&87 ;else Y=&87 COLD RESET
+DA33 INC &028D ;&28D=1
+DA36 INC &028D ;&28D=&28D+1
+DA39 LDA &FC ;Get keyboard links set
+DA3B EOR #&FF ;Invert
+DA3D STA &028F ;and store at &28F
+DA40 LDX #&90 ;X=&90
+
+What we have done is to set up the high water marks for the reset of
+vectors.
+
+&28D=0 Warm reset, X=&9C, Y=&7E
+&28D=1 Power up , X=&90, Y=&8D
+&28D=2 Cold reset, X=&9C, Y=&87
+
+DA42 LDA #&00 ;A=0
+DA44 CPX #&CE ;zero &200+X to &2CD
+DA46 BCC &DA4A ;
+DA48 LDA #&FF ;then set &2CE to &2FF to &FF
+DA4A STA &0200,X ;
+DA4D INX ;
+DA4E BNE &DA44 ;
+ ;A=&FF X=0
+
+This is another IF-GOTO loop, but in this case it is a double function
+loop. The test at DA44 to DA46 means that A is 0 only for values of X
+between the high water mark and &CD. Above this value A is set to &FF
+by the instruction at &DA48. This saves a few bytes of space,
+essential when writing a tightly-filled ROM.
+
+The next instructions set up the printer port. The only reason for
+doing this now is to save two bytes. A must be &FF at this point so it
+is used to set up the User VIA for outputs as the printer port.
+
+DA50 STA &FE63 ;Set port A of user VIA to all outputs (printer out)
+DA53 TXA ;A=0
+DA54 LDX #&E2 ;X=&E2
+
+START OF LOOP
+DA56 STA &00,X ;set zero page addresses &E2 to &FF to zero
+DA58 INX ;
+DA59 BNE &DA56 ;X=0
+
+Now set up the vectors in page 2 from the table at &D940:
+
+DA5B LDA &D93F,Y ;copy data from &D93F+Y
+DA5E STA &01FF,Y ;to &1FF+Y
+DA61 DEY ;until
+DA62 BNE &DA5B ;1FF+Y=&200
+
+Note that this is a decrementing loop which, for loops ending when an
+index register reaches zero, is faster and shorter because no compare
+is needed. More space saved!
+
+Now the RS423 port is set up via a subroutine affecting the ACIA.
+(Asynchronous Communications Interface Adaptor)
+
+DA64 LDA #&62 ;A=&62
+DA66 STA &ED ;store in &ED
+DA68 JSR &FB0A ;set up ACIA ;X=0
+
+Now Acorn clears the interrupt and enable registers of both VIAs.
+
+DA6B LDA #&7F ;bit 7 is 0!
+DA6D INX ;
+DA6E STA &FE4D,X ;
+DA71 STA &FE6D,X ;
+DA74 DEX ;
+DA75 BPL &DA6E ;
+ ;This loop only has two passes as X=0 on entry.
+DA77 CLI ;Briefly allow interrupts to clear anything
+ ;pending
+DA78 SEI ;Disallow again NB: all VIA IRQs are disabled
+DA79 BIT &FC ;If bit 6=1 then JSR &F055 as there must be a
+ ;hardware interrupt!
+DA7B BVC &DA80 ;else DA80
+DA7D JSR &F055 ;
+
+What have we here? Another undocumented routine. If bit 6 of &FC is
+set there must have been a hardware interrupt when the SEI occurred.
+
+From the circuit diagram the only place that this IRQ could have come
+from is the 1MHz bus - let's have a look at the routine at &F055.
+
+F055 JMP (&FDFE) ;Jim paged entry vector
+
+So we jump to some piece of hardware on the 1MHz bus. This would
+probably be a ROM which would take over the system at power on and
+Break. This has some very interesting applications. It was designed by
+Acorn to provide a crude Econet facility to allow a batch of machines
+to be functionally tested without the need to install a full Econet
+kit.
+
+Next week we shall examine the VIA bus.
+
+BBC 6502 Machine Code
+Part Six: The VIA bus
+---------------------
+The next interesting routine we find in the BBC operating system is
+the one that sets up the system VIA interrupts. It is located at
+&DA80. Refer to the manual for the meanings of Sheila addresses.
+
+DA80 LDX #&F2 ;Enable interrupts 1,4,5,6 of system VIA
+DA82 STX &FE4E ;
+ ;0 Keyboard enabled as needed
+ ;1 Frame sync pulse
+ ;4 End of A/D conversion
+ ;5 T2 counter (for speech)
+ ;6 T1 counter (10 mSec intervals)
+
+DA85 LDX #&04 ;set system VIA PCR
+DA87 STX &FE4C ;
+ ;CA1 Interrupt on negative edge (Frame sync)
+ ;CA2 Handshake output for keyboard
+ ;CB1 Interrupt on negative edge (end of conversion)
+ ;CB2 Negative edge (Light pen strobe)
+DA8A LDA #&60 ;Set system VIA ACR
+DA8C STA &FE4B ;
+ ;Disable latching
+ ;Disable shift register
+ ;T1 counter continuous interrupts
+ ;T2 counter timed interrupt
+
+DA8F LDA #&0E ;Set system VIA T1 counter (low)
+DA91 STA &FE46 ;
+ ;This becomes effective when T1 hi set
+DA94 STA &FE6C ;Set user VIA PCR
+ ;CA1 interrupt on -ve edge (Printer Acknowledge)
+DA80 LDX #&F2 ;enable interrupts
+ ;CA2 High output (printer strobe)
+ ;CB1 Interrupt on -ve edge (user port)
+ ;CB2 Negative edge (user port)
+DA97 STA &FEC0 ;Set up A/D converter Bits 0 and 1 determine
+ ;channel selected
+ ;If Bit 3=0 it is set for an 8-bit conversion.
+ ;If bit 3=1 12-bit conversion.
+
+Now although the machine now knows how much RAM it has it still
+doesn't know if it's a Model A or Model B, so it does not know if a
+user VIA is present at &FE60-FE6F.
+
+The next routine tests for the presence of a user VIA. The system
+timers are then set up to interrupt every 10mSec. Sound channels are
+cleared and the serial ULA is set up. Then the function keys are
+reset.
+
+Now we need a catalogue of sideways ROMS. This is not a catalogue in
+the conventional sense as the ROM title is always at the same place in
+the ROM itself and can be read from there. It is a catalogue of the
+ROM types and positions.
+
+There is a ROM latch at &FE30. Writing a number between 0 and 15 to
+this switches the corresponding ROM into the area between &8000 and
+&BFFF. A short subroutine does this and maintains a copy of the
+current ROM in zero page at location &F4.
+
+ ;on entry X=required ROM number
+DC16 STX &F4 ;RAM copy of ROM latch
+DC18 STX &FE30 ;Write to ROM latch
+DC1B RTS ;and return
+
+You should use this subroutine if you want to switch ROMs. Now we can
+look at the ROM cataloguing routines;
+
+A ROM is considered to be valid if it contains a string identical to
+astring at location &DF0C in the Operating System ROM.
+
+DF0C DB ')C(' ;
+DF0F DB 0 ;
+
+The location of this string is pointed to by an offset byte located at
+&8007.
+
+;X=0 on entry
+DABD JSR &DC16 ;Set up ROM latch and RAM copy to X
+DAC0 LDX #&03 ;Set X to point to offset in table
+DA80 LDX #&F2 ;Enable interrupts
+DAC2 LDY &8007 ;Get copyright offset from ROM
+DAC5 LDA &8000,Y ;Get first byte
+DAC8 CMP &DF0C,X ;Compare it with table byte
+DACB BNE &DAFB ;If not the same then goto DAFB
+DACD INY ;Point to next byte
+DACE DEX ;(s)
+DACF BPL &DAC5 ;and if still +ve go back to check next byte.
+ ;This point is reached if 4 bytes indicate
+ ;valid ROM
+
+Next the first 1K of each ROM is checked against higher priority ROMs
+to ensure that there are no matches. If a match is found, the lower
+priority ROM is ignored.
+
+A ROM type byte is located at &8006. A catalogue of these bytes is
+held at &2A1-&2B0. If bit 7 of this byte is 0 then the ROM is BASIC.
+The position of this ROM is stored at &24B.
+
+Now the ROMs are catalogued it is time to set up the speech system and
+screen. More about that next week.
+
+BBC 6502 Machine Code
+Part Seven: Talk to me
+----------------------
+The operating system start-up routines next checks the SPEECH system.
+At this point the X register is set to 16 (&10) by previous routines.
+
+This is one of the reasons why this routine is inserted here. Setting
+X to the required value would use two more bytes. This is not much
+space but it can make the difference between all of the OS fitting
+into a single ROM and a complete hardware or software redesign.
+
+DB11 BIT &FE40 ;If bit 7 low then we have speech system fitted
+DB14 BMI &DB27 ;else goto DB27 for screen set up routine.
+DB16 DEC &027B ;(027B)=&FF a RAM flag that indicates that a speech
+ ;chip is present.
+DB19 LDY #&FF ;Y=&FF
+DB1B JSR &EE7F ;Initialise speech generator
+DB1E DEX ;via this
+DB1F BNE &DB19 ;loop
+
+Now X = 0 so:
+
+DB21 STX &FE48 ;Set T2 timer for speech
+DB24 STX &FE49 ;
+
+Screen set-up
+-------------
+X=0 on entry to this routine which gets the default screen mode and
+then goes off to the screen setup routine.
+
+DB27 LDA &028F ;Get back start up options (mode)
+DB2A JSR &C300 ;then jump to initialise screen.
+
+One of the things that I wondered when I got a BBC was how the RESET
+key could possibly act as a soft key. As we all know BREAK acts as
+soft key 10. But the keyboard buffer is cleared by the Reset. Tucked
+away is the five-byte routine that makes the BREAK key act as soft
+key 10.
+
+Soft keys work by inserting a byte greater than 127 into the keyboard
+buffer. &CA is the code for key 10.
+
+DB2D LDY #&CA ;Y=&CA
+DB2F JSR &E4F1 ;to enter this value in the keyboard buffer
+
+Simple isn't it? You can use the routine yourself although further
+investigation will show that E4F1 is part of an OSbyte call. Remember
+that the keyboard buffer is buffer 0.
+
+E4F1 LDX #&00 ;X=0 keyboard buffer
+
+**************************************
+* *
+* OSBYTE 153 Put byte in input *
+* Buffer checking for ESCAPE *
+* *
+**************************************
+
+On entry X = buffer number which is either 0 or 1. If it's 0 then the
+keyboard buffer is selected. If it's 1 then it is the RS423 buffer.
+
+Notice that the JSR to EF41 ensures that ONLY the keyboard buffer can
+be selected. Once again we are looking at coding economy, in this case
+with a specific keyboard buffer entry routine. Y contains the
+character to be written.
+
+E4F3 TXA ;A=buffer number
+E4F4 AND &0245 ;and with RS423 mode (0 treat as keyboard 1 ignore
+ ;Escapes no events no soft keys)
+E4F7 BNE &E4AF ;so if RS423 buffer AND RS423 in normal mode (1) E4AF
+ ;
+E4F9 TYA ;else Y=A character to write
+E4FA EOR &026C ;compare with current escape ASCII code (0=match)
+E4FD ORA &0275 ;or with current ESCAPE status (0=ESC, 1=ASCII)
+E500 BNE &E4A8 ;if ASCII or no match E4A8 to enter byte in buffer
+E502 LDA &0258 ;else get ESCAPE / BREAK action byte
+E505 ROR ;Rotate to get ESCAPE bit into carry
+E506 TYA ;get character back in A
+E507 BCS &E513 ;and if escape disabled exit with carry clear
+E509 LDY #&06 ;else signal EVENT 6 Escape pressed
+E50B JSR &E494 ;
+E50E BCC &E513 ;if event handles ESCAPE then exit with carry clear
+E510 JSR &E674 ;else set ESCAPE flag
+E513 CLC ;clear carry
+E514 RTS ;and exit
+
+This routine will normally be accessed by assembly language
+programmers by OSbyte 138 which calls EF43.
+
+BBC 6502 Machine Code
+Part Eight: Breaker Break
+-------------------------
+One of the 'secret' features of the BBC Micro OS 1.20 when it was
+arrived was the BREAK intercept. This is a useful method of taking
+over the machine and is sometimes used by ROM software.
+
+There are two entry points, entered with the carry flag reset to 0 and
+set to 1 respectively. The first call comes before sideways ROM calls.
+
+Enter BREAK intercept with Carry Clear
+
+DB32 JSR &EAD9 ;check to see if BOOT address is set up if so
+ ;JMP to it
+
+The address &287 is written by OSbyte 247 and the jump addresses in
+&288 and &289 by OSbytes 248 and 249. The machine code for JMP is &4C.
+
+EAD9 LDA &0287 ;get BREAK vector code
+EADC EOR #&4C ;produces 0 if JP (4C) not in &287
+EADE BNE &EAF3 ;if not goto EAF3
+EAE0 JMP &0287 ;else jump to use BREAK code
+EAF3 RTS ;Return
+
+The RTS at the end of another routine is used because it saves code.
+
+Frequently you will find machine code routines where a lot of branches
+go to a single RTS for just this reason. If you are writing your own
+code remember that the RTS must be within range of the branch. One of
+the most common assembler errors is a branch out of range that in turn
+causes more errors when you add an extra RTS.
+
+Obviously at this point the machine could be totally in your control.
+You can return control to the OS with an RTS or just continue on your
+merry way.
+
+Remember that the sideways ROMs don't have any workspace yet and you
+can't really run BASIC or any other language as the workspace will not
+exist. But, assuming that you don't want to do any of this, let's go
+back to the OS routines after testing for BREAK intercept.
+
+DB35 JSR &F140 ;set up cassette options
+DB38 LDA #&81 ;test for tube to FIFO buffer 1
+DB3A STA &FEE0 ;
+DB3D LDA &FEE0 ;
+DB40 ROR ;put bit 0 into carry
+DB41 BCC &DB4D ;if no tube then DB4D
+DB43 LDX #&FF ;else
+DB45 JSR &F168 ;issue ROM service call &FF to initialise TUBE system
+DB48 BNE &DB4D ;if not 0 on exit (tube not initialised) DB4D
+DB4A DEC &027A ;else set tube flag to show its active
+
+Now the Tube is flagged as active, or not as the case may be. We
+continue next week, with the setup routines for the sideways ROMs.
+
+BBC 6502 Machine Code
+Part Nine: A ROM with a view
+-----------------------------
+Now we nearly have a working system, we are, perhaps, 400 milliseconds
+into the Power up routine. Now is the time to set up all of those nice
+sideways ROMs we catalogued earlier.
+
+First we set up workspace and hence the value of BASIC's PAGE
+variable. The call to ROMs is made via F168. This is available to the
+programmer as OSBYTE 143.
+
+A ROM can have a number between 0 and 15 and will have two entry
+points - a Service entry at &8003 and a Language entry at &8000. If
+the ROM does not contain language code it will not have a language
+entry.
+
+ROMs are paged into main memory by writing the ROM number to a latch
+at &FE30. Hardware could be arranged to allow 256 ROMs although the
+operating system does not support this.
+
+The Break Intercept code could be used to make drastic hardware
+modifications like this.
+
+**************************************
+* *
+* OSBYTE 143 *
+* Pass service commands *
+* to sideways ROMs *
+* *
+**************************************
+ ;on entry X=command number
+F168 LDA &F4 ;get current ROM number
+F16A PHA ;store it
+F16B TXA ;command in A
+F16C LDX #&0F ;set X=15
+
+The next bit of code is a countdown loop to send the command code to
+each enabled ROM in turn. The Map at &2A1 is used to decide which ROMs
+are active. Note the use of a countdown loop. This gives code economy
+and explains why the highest ROM number has priority.
+
+F16E INC &02A1,X ;read bit 7 on ROM map (no ROM has type 254 &FE)
+F171 DEC &02A1,X ;
+F174 BPL &F183 ;if not set (+ve result)
+F176 STX &F4 ;else store ROM number in &F4
+F178 STX &FE30 ;switch in paged ROM
+F17B JSR &8003 ;and jump to service entry
+F17E TAX ;on exit put A in X
+F17F BEQ &F186 ;if 0 (command recognised by ROM) reset ROMs & exit
+F181 LDX &F4 ;else point to next lower ROM
+F183 DEX ;
+F184 BPL &F16E ;and go round loop again
+F186 PLA ;get back original ROM number
+F187 STA &F4 ;store it in RAM copy
+F189 STA &FE30 ;select original page
+F18C TXA ;put X back in A
+F18D RTS ;and return
+
+Couldn't be easier! So we can now return to the main body of the
+routine.
+
+DB4D LDY #&0E ;set current value of PAGE
+DB4F LDX #&01 ;issue call to claim absolute workspace
+DB51 JSR &F168 ;via F168
+DB54 LDX #&02 ;send private workspace claim call
+DB56 JSR &F168 ;via F168
+
+OSHWM is OS High Water Mark. The highest address used by the operating
+system.
+
+DB59 STY &0243 ;set primary OSHWM
+DB5C STY &0244 ;set current OSHWM
+DB5F LDX #&FE ;issue call for Tube to explode character set etc.
+DB61 LDY &027A ;Y=FF if tube present else Y=0
+DB64 JSR &F168 ;and make call via F168
+
+We now have the machine set up to enter a language, all the filing
+systems have been set up and the sideways ROMs activated.
+
+Next week we finally start the screen messages.
+
+BBC 6502 Machine Code
+Part Ten: Stringing it along
+-----------------------------
+The next routine shows why the Machine start up message is not always
+seen on third-party kit.
+
+DB67 AND &0267 ;if A=&FE and bit 7 of 0267 is set then continue
+DB6A BPL &DB87 ;else ignore start up message
+DB6C LDY #&02 ;output to screen
+DB6E JSR &DEA9 ;'BBC Computer ' message
+
+Looking at the routine in DEA9 we find a very useful string printing
+routine. Remember that Y = 2 on entry.
+
+DEA9 LDA #&C3 ;point to start &C300
+DEAB STA &FE ;store it
+DEAD LDA #&00 ;point to lo byte
+DEAF STA &FD ;store it and start loop with Y=2
+DEB1 INY ;print character in string
+DEB2 LDA (&FD),Y ;pointed to by &FD/E +Y
+DEB4 JSR OSASCI ;print it expanding Carriage returns
+DEB7 TAX ;store A in X
+DEB8 BNE &DEB1 ;and loop again if not =0
+DEBA RTS ;else exit
+
+Here is the string delimited by BRK. The code for BRK is 00. Y is 3
+when the first character is read so its address is &C303.
+
+C303 DB 13 ;Carriage Return
+C304 DB 'BBC Computer '
+C311 BRK
+
+Notice that the routine uses TAX to set the zero flag which marks the
+end of the string. This is a useful tip.
+
+The next part of the Operating system deals with printing correct
+messages on the screen.
+
+DB71 LDA &028D ;0=warm reset, If a cold reset continue
+DB74 BEQ &DB82 ;
+DB76 LDY #&16 ;by checking length of RAM
+DB78 BIT &028E ;
+DB7B BMI &DB7F ;and either
+DB7D LDY #&11 ;
+DB7F JSR &DEA9 ;finishing message with '16K' or '32K'
+DB82 LDY #&1B ;and two new lines
+DB84 JSR &DEA9 ;
+
+Notice that Y is used to pick the appropriate message.
+
+C312 DB '16K'
+C315 DB 7 ;Bell
+C316 BRK
+C317 DB '32K'
+C31A DB 7 ;Bell
+C31B BRK
+C31C DB 08,0D,0D
+
+Notice the BBC Beep at this point indicates that nearly all set up
+procedures have been finished.
+
+The hum is generated by the Sound channel which is reset as part of
+the start routine. Hence the HUM-BEEP start up. If the machine does
+not start properly the sound signals give a strong clue to the nature
+of the problem. Having got this far the OS gives us another chance to
+take control.
+
+Enter BREAK INTERCEPT ROUTINE WITH CARRY SET (call 1)
+
+DB87 SEC ;
+DB88 JSR &EAD9 ;look for break intercept jump
+ ;SEE EARLIER PART
+
+Next we set up the keyboard lights
+
+DB8B JSR &E9D9 ;set up LEDs in accordance with keyboard status
+
+This is another 'undocumented' OSBYTE call.
+
+**************************************
+* *
+* OSBYTE &76 (118) *
+* SET LEDs to Keyboard Status *
+* *
+**************************************
+;osbyte entry with carry set
+E9D9 PHP ;PUSH P
+E9DA SEI ;DISABLE INTERRUPTS
+E9DB LDA #&40 ;switch on CAPS and SHIFT lock lights
+E9DD JSR &E9EA ;via subroutine
+E9E0 BMI &E9E7 ;if ESCAPE exists (M set) E9E7
+E9E2 CLC ;else clear V and C
+E9E3 CLV ;before calling main keyboard routine to
+E9E4 JSR &F068 ;switch on lights as required
+E9E7 PLP ;get back flags
+E9E8 ROL ;and rotate carry into bit 0
+E9E9 RTS ;Return to calling routine
+ ;
+* Turn on keyboard lights and
+* Test Escape flag
+ ;
+E9EA BCC &E9F5 ;if carry clear
+E9EC LDY #&07 ;switch on shift lock light
+E9EE STY &FE40 ;
+E9F1 DEY ;Y=6
+E9F2 STY &FE40 ;switch on Caps lock light
+E9F5 BIT &FF ;set minus flag if bit 7 of &00FF is set indicating
+E9F7 RTS ;that ESCAPE condition exists, then return
+
+The Keyboard routine continues via the KEYV. This is a little long to
+include here so we'll leave it until a later part. So back to the
+Start up routine next week with the cassette system.
+
+BBC 6502 Machine Code
+Part Eleven: Language!
+----------------------
+Having got the keyboard nicely set up the machine proceeds to
+initialise a filing system and run a !BOOT file if one exists. The
+start up options are already read from the keyboard links.
+
+DB8E PHP ;save flags
+DB8F PLA ;and get back in A
+DB90 LSR ;zero bits 4-7 and bits 0-2 bit 4 which was bit 7
+DB91 LSR ;may be set
+DB92 LSR ;
+DB93 LSR ;
+DB94 EOR &028F ;EOR with start up options which may or may not
+DB97 AND #&08 ;invert bit 4
+DB99 TAY ;Y=A
+DB9A LDX #&03 ;make initialisation call, if Y=0 on entry
+DB9C JSR &F168 ;RUN, EXEC or LOAD !BOOT file from a filing system.
+DB9F BEQ &DBBE ;if a ROM accepts this call then DBBE
+DBA1 TYA ;else put Y in A
+DBA2 BNE &DBB8 ;if Y<>0 DBB8
+DBA4 LDA #&8D ;else set up standard cassette baud rates
+DBA6 JSR &F135 ;via &F135 which is OSBYTE 140.
+DBA9 LDX #&D2 ;
+DBAB LDY #&EA ;
+DBAD DEC &0267 ;decrement ignore start up message flag
+DBB0 JSR OSCLI ;and execute /!BOOT
+DBB3 INC &0267 ;restore start up message flag
+DBB6 BNE &DBBE ;if not zero then DBBE
+DBB8 LDA #&00 ;else A=0
+DBBA TAX ;X=0
+DBBB JSR &F137 ;set tape speed via OSBYTE 140.
+
+We now have an active filing system. The next job is to preserve the
+current language on soft RESET.
+
+DBBE LDA &028D ;get last RESET Type
+DBC1 BNE &DBC8 ;if not soft reset DBC8
+DBC3 LDX &028C ;else get current language ROM address
+DBC6 BPL &DBE6 ;if +ve (language available) then skip search
+ ;routine
+For a cold break we search for the language with the highest priority.
+
+DBC8 LDX #&0F ;set pointer to highest available ROM
+DBCA LDA &02A1,X ;get ROM type from map
+DBCD ROL ;put hi-bit into carry, bit 6 into bit 7
+DBCE BMI &DBE6 ;if bit 7 set then ROM has a language entry so DBE6
+DBD0 DEX ;else search for language until X=&ff
+
+Check for Tube if no language found.
+
+DBD1 BPL &DBCA ;check if tube present
+DBD3 LDA #&00 ;if bit 7 of tube flag is set BMI succeeds
+DBD5 BIT &027A ;and TUBE is connected else
+DBD8 BMI &DC08 ;make error
+
+No language error
+
+DBDA BRK ;
+DBDB DB &F9 ;error number
+DBDC DB 'Language?' ;message
+DBE5 BRK ;
+
+This might seem odd as BRK is handled by the current language BRK
+handler, but we don't have a language! We need to investigate further
+in another part.
+
+DBE6 CLC ;
+
+OSBYTE 142 enter Language ROM at &8000 X=ROM number. Carry is set if
+this is an OSBYTE call and clear if this is an initialisation routine.
+
+DBE7 PHP ;save flags
+DBE8 STX &028C ;put X in current ROM page
+DBEB JSR &DC16 ;select that ROM
+DBEE LDA #&80 ;A=128
+DBF0 LDY #&08 ;Y=8
+DBF2 JSR &DEAB ;display text string held in ROM at &8008,Y
+DBF5 STY &FD ;save Y on exit (end of language string)
+DBF7 JSR OSNEWL ;two line feeds
+DBFA JSR OSNEWL ;are output
+DBFD PLP ;then get back flags
+DBFE LDA #&01 ;A=1 required for language entry
+DC00 BIT &027A ;check if tube exists
+DC03 BMI &DC08 ;and goto DC08 if it does
+DC05 JMP &8000 ;else enter language at &8000
+
+TUBE FOUND enter tube software
+
+DC08 JMP &0400 ;enter tube environment
+
+The Tube initialisation would have read the language across to the
+TUBE usually but it could be loaded by a !BOOT file from the filing
+system initialisation.
+
+The operating system now stops general control of the system and hands
+this to the language which looks after command lines etc. The OS
+however still handles the screen, keyboard and much else.
+
+Notice how every possible eventuality was taken into account during
+the initialisation routine. This is one of the things that made the
+Beeb a very powerful machine.
+
+Next week we'll have a look at the Interrupt code.
+
+BBC 6502 Machine Code
+Part Twelve: Pardon me!
+-----------------------
+We finished the last part at the point where the operating systems
+power up routine handed over control to the language. We'll write our
+own language later in the series but for now let's dive into another
+entry point.
+
+When the processor's IRQ pin (4) goes low (0V) the processor finishes
+off the current instruction and then goes off to run some microcode of
+its own. This checks that the RDY (2) pin is high and that the
+interrupt flag in the status register is 0 (not set). If it is set the
+interrupt is ignored and the processor goes to the next instruction.
+This continues when the IRQ pin is low.
+
+If the flag is clear then the processor stores the program counter and
+status register on the stack and sets the interrupt flag. The 6502
+then gets the address stored in &FFFE and &FFFF and executes this
+instruction next.
+
+If a BRK instruction is found in executing code then the processor
+performs exactly the same actions except that it does not check the
+status register for the interrupt flag, it does set a flag in the
+status register, the BRK flag.
+
+The main entry point for IRQ (and BRK) for OS 1.20 is &DC51.
+
+MAIN IRQ Entry point
+
+;ON ENTRY STACK contains STATUS REGISTER,PCH,PCL
+DC1C STA &FC ;save A
+DC1E PLA ;get back status (flags)
+DC1F PHA ;and save again
+DC20 AND #&10 ;check if BRK flag set
+DC22 BNE &DC27 ;if so goto DC27
+DC24 JMP (&0204) ;else JUMP through IRQ1V
+
+That's pretty straightforward so far. As you can see IRQ1V allows you
+to put your own hardware at a higher priority than anything else in
+the machine.
+
+You can also write your own hardware interrupt handler if you wish.
+This is the flexibility that made the BBC machine so remarkably
+successful among knowledgeable users.
+
+Let's look at the BRK handler now.
+
+* BRK handling routine *
+DC27 TXA ;save X on stack
+DC28 PHA ;
+DC29 TSX ;get status pointer
+DC2A LDA &0103,X ;get Program Counter low byte
+DC2D CLD ;
+DC2E SEC ;set carry
+DC2F SBC #&01 ;subtract 2 (1+carry)
+DC31 STA &FD ;and store it in &FD
+DC33 LDA &0104,X ;get hi byte
+DC36 SBC #&00 ;subtract 1 if necessary
+DC38 STA &FE ;and store in &FE
+DC3A LDA &F4 ;get currently active ROM
+DC3C STA &024A ;and store it in &24A
+DC3F STX &F0 ;store stack pointer in &F0
+DC41 LDX #&06 ;and issue ROM service call 6
+DC43 JSR &F168 ;(User BRK) to ROMs
+ ;now &FD/E points to byte after BRK
+ ;ROMS may use BRK for their own purposes
+ ;and many do!
+
+It's interesting to see what happens with the ROM handler. This is
+also an entry point for OSBYTE 143 so you can use this in your own
+code.
+
+* OSBYTE 143 *
+*Pass service commands to sideways ROMs *
+ ;on entry X=command number
+F168 LDA &F4 ;get current ROM number
+F16A PHA ;store it
+F16B TXA ;command in A
+F16C LDX #&0F ;set X=15
+ ;send commands loop
+F16E INC &02A1,X ;read bit 7 on ROM map (no ROM has
+ ;type 254 &FE)
+F171 DEC &02A1,X ;
+F174 BPL &F183 ;if not set (+ve result)
+F176 STX &F4 ;else store ROM number in &F4
+F178 STX &FE30 ;switch in paged ROM
+F17B JSR &8003 ;and jump to service entry
+F17E TAX ;on exit put A in X
+F17F BEQ &F186 ;if 0 (command recognised by ROM)
+ ;reset ROMs & exit
+F181 LDX &F4 ;else point to next lower ROM
+F183 DEX ;
+F184 BPL &F16E ;and go round loop again
+F186 PLA ;get back original ROM number
+F187 STA &F4 ;store it in RAM copy
+F189 STA &FE30 ;select original page
+F18C TXA ;put X back in A
+F18D RTS ;and return
+
+Useful little routine that. So back to the BRK handler.
+
+DC46 LDX &028C ;get current language
+DC49 JSR &DC16 ;and activate it
+DC4C PLA ;get back original value of X
+DC4D TAX ;
+DC4E LDA &FC ;get back original value of A
+DC50 CLI ;allow interrupts
+DC51 JMP (&0202) ;and JUMP via BRKV (normally into current language)
+
+Next week we'll carry on by taking a look at the BRK handler.
+
+BBC 6502 Machine Code
+Part Thirteen: Give us a BRK
+----------------------------
+BRK is usually handled by the default language (or by a Sideways ROM).
+However, it may be that you are running a machine code program before
+a current language is set up or perhaps your language doesn't handle
+BRK (it should but you never know).
+
+That's when a default BRK handler takes over.
+
+* DEFAULT BRK HANDLER *
+
+DC54 LDY #&00 ;Y=0 to point to byte after BRK
+DC56 JSR &DEB1 ;print message
+
+Let's have a look at the print routine. Remember that the error-
+handling layout is:
+
+BRK
+Error Number (1 byte)
+Message
+BRK
+
+Y plus the address in &FD &FE points to the error message on entry.
+
+DEB1 INY ;point to first ;character in string
+DEB2 LDA (&FD),Y
+DEB4 JSR OSASCI ;print it
+ ;expanding
+ ;Carriage
+ ;returns
+DEB7 TAX ;store A in X to change flags
+DEB8 BNE &DEB1 ;and loop again if not =0
+DEBA RTS ;else exit
+
+A standard print routine, nothing out of the ordinary but nice and
+compact.
+
+You can use this in your own print routines by changing the zero page
+values. Back to the default BRK handler and an interesting bit of
+code.
+
+DC59 LDA &0267 ;if BIT 0 set and DISK EXEC error
+DC5C ROR ;occurs
+DC5D BCS &DC5D ;hang up machine!
+
+Nasty! But the machine has to be in a pretty unusual configuration for
+this to happen. Mind you, setting 0267 then doing a JSR to DC59 would
+confuse the average user.
+
+DC5F JSR OSNEWL ;else print two newlines
+DC62 JSR OSNEWL ;
+DC65 JMP &DBB8 ;and set tape speed before entering the current
+ ;language
+DBB8 LDA #&00 ;else A=0
+DBBA TAX ;X=0
+DBBB JSR &F137 ;set tape speed via OSBYTE 141.
+
+There's the end of the BRK handling code. As I said before this is
+generally handled by the default language but you can arrange for your
+own code or a Sideways ROM to handle it.
+
+Next week we'll return to the interrupt system with a look at the
+default entry point for IRQ1.
+
+BBC 6502 Machine Code
+Part Fourteen: The story so far...
+----------------------------------
+We left the interrupt-handling routine just after it had gone off to
+the IRQ1V vector. If you don't change the vector the code continues
+from DC93.
+
+One very important thing to remember about an interrupt-driven machine
+like the BBC is that the interrupt flag is not set for too long. If it
+is the machine could crash. This means that interrupt routines are
+short and snappy.
+
+* Main IRQ Handling routines, default IRQIV destination *
+
+DC93 CLD ;clear decimal flag
+DC94 LDA &FC ;get original value of A
+DC96 PHA ;save it
+DC97 TXA ;save X
+DC98 PHA ;
+DC99 TYA ;and Y
+DC9A PHA ;on the stack
+ ;note the pre-CMOS code!
+DC9B LDA #&DE ;A=&DE
+DC9D PHA ;store it
+DC9E LDA #&81 ;save &81
+DCA0 PHA ;store it (a RTS will now jump to DE82)
+
+This is quite a useful technique as we will see later. If we now use
+JMP to go to an OS routine we can ensure that the routine, which ends
+with an RTS, causes execution to go to a specified point.
+
+This saves a lot of code as it can be arranged that the first device
+found that called the interrupt will be the only one handled. This, in
+turn, saves time!
+
+We now poll the hardware looking for who caused it. The first routine
+deals with the serial/tape system.
+
+DCA1 CLV ;clear V flag
+DCA2 LDA &FE08 ;get value of status register of ACIA
+DCA5 BVS &DCA9 ;if this was source then DCA9 to process
+DCA7 BPL &DD06 ;else if no interrupt requested DD06
+DCA9 LDX &EA ;read RS423 timeout counter
+DCAB DEX ;decrement it
+DCAC BMI &DCDE ;and if <0 DCDE
+DCAE BVS &DCDD ;else if >&40 DCDD (RTS to DE82)
+DCB0 JMP &F588 ;else read ACIA via F588
+ ;RTS ends routine!!
+DCB3 LDY &FE09 ;read ACIA data
+DCB6 ROL ;
+DCB7 ASL ;
+DCB8 TAX ;X=A
+DCB9 TYA ;A=Y
+DCBA LDY #&07 ;Y=07
+DCBC JMP &E494 ;check and service EVENT 7 RS423 error
+DCBF LDX #&02 ;read RS423 output buffer
+DCC1 JSR &E460 ;
+DCC4 BCC &DCD6 ;if C=0 buffer is not empty goto DCD6
+DCC6 LDA &0285 ;else read printer destination
+DCC9 CMP #&02 ;is it serial printer??
+DCCB BNE &DC68 ;if not DC68
+DCCD INX ;else X=3
+DCCE JSR &E460 ;read printer buffer
+DCD1 ROR &02D2 ;rotate to pass carry into bit 7
+DCD4 BMI &DC68 ;if set then DC68
+DCD6 STA &FE09 ;pass either printer or RS423 data to ACIA
+DCD9 LDA #&E7 ;set timeout counter to stored value
+DCDB STA &EA ;
+DCDD RTS ;and exit (to DE82)
+
+ ;A contains ACIA status
+DCDE AND &0278 ;AND with ACIA bit mask (normally FF)
+DCE1 LSR ;rotate right to put bit 0 in carry
+DCE2 BCC &DCEB ;if carry clear receive register not full so DCEB
+DCE4 BVS &DCEB ;if V is set then DCEB
+DCE6 LDY &0250 ;else Y=ACIA control setting
+DCE9 BMI &DC7D ;if bit 7 set receive interrupt is enabled so DC7D
+
+DCEB LSR ;put BIT 2 of ACIA status into
+DCEC ROR ;carry if set then Data Carrier Detected applies
+DCED BCS &DCB3 ;jump to DCB3
+
+DCEF BMI &DCBF ;if original bit 1 is set TDR is empty so DCBF
+DCF1 BVS &DCDD ;if V is set then exit to DE82
+
+DCF3 LDX #&05 ;X=5
+DCF5 JSR &F168 ;issue ROM call 5 'unrecognised ;interrupt'
+
+We've seen this ROM service routine call before.
+
+DCF8 BEQ &DCDD ;if a ROM recognises it then exit to DE82
+DCFA PLA ;otherwise get back DE82 address from stack
+DCFB PLA ;
+DCFC PLA ;and get back X, Y and A
+DCFD TAY ;
+DCFE PLA ;
+DCFF TAX ;
+DD00 PLA ;
+DD01 STA &FC ;&FC=A
+DD03 JMP (&0206) ;and offer to the user via IRQ2V
+
+That was a little convoluted, to say the least. Next week we look at how the
+VIAs are dealt with.
+
+BBC 6502 Machine Code
+Part Fifteen: Hardware VIA interrupts
+-------------------------------------
+After deciding that it wasn't the ACIA that caused the interrupt, the
+VIAs are the next port of inquisition.
+
+* VIA INTERRUPTS ROUTINES *
+
+DD06 LDA &FE4D ;read system VIA interrupt flag register
+DD09 BPL &DD47 ;if bit 7=0 the VIA has not caused interrupt goto DD47
+
+DD0B AND &0279 ;mask with VIA bit mask
+DD0E AND &FE4E ;and interrupt enable register
+DD11 ROR ;rotate right twice to ;check for IRQ 1 (frame sync)
+
+DD12 ROR ;
+DD13 BCC &DD69 ;if carry clear then no IRQ 1, else IRQ 1 means
+ ;interrupt request 1. This is different from the
+ ;vector IRQ1.
+
+DD15 DEC &0240 ;decrement vertical sync counter
+DD18 LDA &EA ;A=RS423 Timeout counter
+DD1A BPL &DD1E ;if +ve then DD1E
+DD1C INC &EA ;else increment it
+DD1E LDA &0251 ;load flash character counter
+DD21 BEQ &DD3D ;if 0 then flash system is not in use, ignore it
+DD23 DEC &0251 ;else decrement counter
+DD26 BNE &DD3D ;and if not 0 go on past reset routine
+
+This routine resets the flashing character system.
+
+DD28 LDX &0252 ;get mark period count in X
+DD2B LDA &0248 ;current VIDEO ULA control setting in A
+DD2E LSR ;shift bit 0 into C to ;check if first colour
+DD2F BCC &DD34 ;is effective if so C=0. Jump to DD34
+DD31 LDX &0253 ;else get space period count in X
+DD34 ROL ;restore bit
+DD35 EOR #&01 ;and invert it
+DD37 JSR &EA00 ;then change colour
+
+DD3A STX &0251 ;&0251=X resetting the counter
+
+DD3D LDY #&04 ;Y=4 and call E494 to check and implement vertical
+DD3F JSR &E494 ;sync event (4) if necessary
+DD42 LDA #&02 ;A=2
+DD44 JMP &DE6E ;clear interrupt 1 and exit
+
+Remember the RTS routine last time?
+
+* PRINTER INTERRUPT USER VIA 1 *
+
+DD47 LDA &FE6D ;Check USER VIA interrupt flags register
+DD4A BPL &DCF3 ;if +ve USER VIA did not call interrupt
+DD4C AND &0277 ;else check for USER IRQ 1 printer interrupt.
+DD4F AND &FE6E ;
+DD52 ROR ;
+DD53 ROR ;
+DD54 BCC &DCF3 ;if bit 1=0 then no ;interrupt 1 so DCF3
+DD56 LDY &0285 ;else get printer type
+DD59 DEY ;decrement
+DD5A BNE &DCF3 ;if not parallel then :CF3
+DD5C LDA #&02 ;reset interrupt 1 flag
+DD5E STA &FE6D ;
+DD61 STA &FE6E ;disable interrupt 1
+DD64 LDX #&03 ;and output data to parallel printer
+DD66 JMP &E13A ;and exit via RTS
+
+* SYSTEM INTERRUPT 5 Speech *
+
+DD69 ROL ;get bit 5 into bit 7
+DD6A ROL ;
+DD6B ROL ;
+DD6C ROL ;
+DD6D BPL &DDCA ;if not set this is not ;a speech interrupt so DDCA
+DD6F LDA #&20 ;
+DD71 LDX #&00 ;
+DD73 STA &FE4D ;
+DD76 STX &FE49 ;and zero high byte of Timer t2
+DD79 LDX #&08 ;&FB=8
+DD7B STX &FB ;
+DD7D JSR &E45B ;and examine buffer 8
+DD80 ROR &02D7 ;shift carry into bit 7
+DD83 BMI &DDC9 ;and if set buffer is empty so exit
+DD85 TAY ;else Y=A
+DD86 BEQ &DD8D ;
+DD88 JSR &EE6D ;control speech chip
+DD8B BMI &DDC9 ;if negative exit
+DD8D JSR &E460 ;else get a byte from buffer
+DD90 STA &F5 ;store it to indicate speech or file ROM
+DD92 JSR &E460 ;get another byte
+DD95 STA &F7 ;store it
+DD97 JSR &E460 ;and another
+DD9A STA &F6 ;giving address to be accessed in paged ROM
+DD9C LDY &F5 ;Y=&F5
+DD9E BEQ &DDBB ;and if =0 then DDBB
+DDA0 BPL &DDB8 ;else if +ve DDB8
+DDA2 BIT &F5 ;if bit 6 of F5 =1 (&F5)>&40
+DDA4 BVS &DDAB ;then DDAB
+DDA6 JSR &EEBB ;else continue for more speech processing
+DDA9 BVC &DDB2 ;if bit 6 clear then DDB2
+DDAB ASL &F6 ;else double address in &F6/7
+DDAD ROL &F7 ;
+DDAF JSR &EE3B ;and call EE3B
+DDB2 LDY &0261 ;get speech enable/disable flag into Y
+DDB5 JMP &EE7F ;and JMP to EE7F
+
+DDB8 JSR &EE7F ;Call EE7F
+DDBB LDY &F6 ;get address pointer in Y
+DDBD JSR &EE7F ;
+DDC0 LDY &F7 ;get address pointer high in Y
+DDC2 JSR &EE7F ;
+DDC5 LSR &FB ;
+DDC7 BNE &DD7D ;
+DDC9 RTS ;and exit
+
+Next week we continue with a look at the remaining System Interrupts.
+
+BBC 6502 Machine Code
+Part Sixteen: Timers and Keyboard Interrupts
+--------------------------------------------
+The last part showed how the BBC Micro handles some of the system
+interrupt calls. Most of these are pretty routine so we won't continue
+with an interminable list.
+
+The next interesting routines concern how the timers and keyboard
+interrupts are handled.
+
+* SYSTEM INTERRUPT 6 10mS Clock *
+
+DDCA BCC &DE47 ;bit 6 is in carry so if clear there is no 6 so go
+ ;on to DE47
+DDCC LDA #&40 ;Clear interrupt 6
+DDCE STA &FE4D ;
+
+This is the start of the update timers routine, This is interesting
+because of the way that the timer information is stored. It's very
+clever. There are two timer stores, &292-6 and &297-B. These are
+updated by adding 1 to the current timer and storing the result in the
+other, the direction of transfer being changed each time of update.
+
+This ensures that at least one timer is valid at any call as the
+current timer only is read. Other methods would cause inaccuracies if
+a timer was read while being updated.
+
+DDD1 LDA &0283 ;get current system clock store pointer (5,or 10)
+DDD4 TAX ;put A in X
+DDD5 EOR #&0F ;and invert lo nybble (5becomes 10 and vv)
+DDD7 PHA ;store A
+DDD8 TAY ;put A in Y. Carry is always set at this point
+DDD9 LDA &0291,X ;get timer value
+DDDC ADC #&00 ;update it
+DDDE STA &0291,Y ;store result in alternate
+DDE1 DEX ;decrement X
+DDE2 BEQ &DDE7 ;if 0 exit
+DDE4 DEY ;else decrement Y
+DDE5 BNE &DDD9 ;and go back and do next byte
+DDE7 PLA ;get back A
+DDE8 STA &0283 ;and store back in clock pointer (ie. inverse
+ ;previous contents)
+DDEB LDX #&05 ;set loop pointer for countdown timer
+DDED INC &029B,X ;increment byte and
+DDF0 BNE &DDFA ;if not 0 then DDFA
+DDF2 DEX ;else decrement pointer
+DDF3 BNE &DDED ;and if not 0 do it again
+DDF5 LDY #&05 ;process EVENT 5 interrupt timer
+DDF7 JSR &E494 ;
+DDFA LDA &02B1 ;get byte of inkey countdown timer
+DDFD BNE &DE07 ;if not 0 then DE07
+DDFF LDA &02B2 ;else get next byte
+DE02 BEQ &DE0A ;if 0 DE0A
+DE04 DEC &02B2 ;decrement 2B2
+DE07 DEC &02B1 ;and 2B1
+DE0A BIT &02CE ;read bit 7 of envelope processing byte
+DE0D BPL &DE1A ;if 0 then DE1A
+DE0F INC &02CE ;else increment to 0
+DE12 CLI ;allow interrupts
+DE13 JSR &EB47 ;and do routine sound processes
+DE16 SEI ;bar interrupts
+DE17 DEC &02CE ;DEC envelope processing byte back to 0
+DE1A BIT &02D7 ;read speech buffer busy flag
+DE1D BMI &DE2B ;if set speech buffer is empty, skip routine
+DE1F JSR &EE6D ;update speech system variables
+DE22 EOR #&A0 ;
+DE24 CMP #&60 ;
+DE26 BCC &DE2B ;if result >=&60 DE2B
+DE28 JSR &DD79 ;else more speech work
+DE2B BIT &D9B7 ;set V and C
+DE2E JSR &DCA2 ;check if ACIA needs attention
+DE31 LDA &EC ;check if key has been pressed
+DE33 ORA &ED ;
+DE35 AND &0242 ;(this is 0 if keyboard is to be ignored, else
+ ;&FF)
+DE38 BEQ &DE3E ;if 0 ignore keyboard
+DE3A SEC ;else set carry
+DE3B JSR &F065 ;and call keyboard
+DE3E JSR &E19B ;check for data in use defined printer channel
+DE41 BIT &FEC0 ;if ADC bit 6 is set ADC is not busy
+DE44 BVS &DE4A ;so DE4A
+DE46 RTS ;else return
+
+* SYSTEM INTERRUPT 4 ADC end of conversion *
+
+DE47 ROL ;put original bit 4 from FE4D into bit 7 of A
+DE48 BPL &DE72 ;if not set DE72
+DE4A LDX &024C ;else get current ADC channel
+DE4D BEQ &DE6C ;if 0 DE6C
+DE4F LDA &FEC2 ;read low data byte
+DE52 STA &02B5,X ;store it in &2B6,7,8 or 9
+DE55 LDA &FEC1 ;get high data byte
+DE58 STA &02B9,X ;and store it in hi byte
+DE5B STX &02BE ;store in Analogue system flag marking last channel
+DE5E LDY #&03 ;handle event 3 conversion complete
+DE60 JSR &E494 ;
+DE63 DEX ;decrement X
+DE64 BNE &DE69 ;if X=0
+DE66 LDX &024D ;get highest ADC channel present
+DE69 JSR &DE8F ;and start new conversion
+DE6C LDA #&10 ;reset interrupt 4
+DE6E STA &FE4D ;
+DE71 RTS ;and return
+
+* SYSTEM INTERRUPT 0 Keyboard *
+
+DE72 ROL ;get original bit 0 in bit 7 position
+DE73 ROL ;
+DE74 ROL ;
+DE75 ROL ;
+DE76 BPL &DE7F ;if bit 7 clear not a keyboard interrupt
+DE78 JSR &F065 ;else scan keyboard
+DE7B LDA #&01 ;A=1
+DE7D BNE &DE6E ;and off to reset interrupt and exit
+DE7F JMP &DCF3 ;and again a subroutine to exit.
+
+Now we come to the point you've all been waiting for. This mystery
+RTSreturns all subroutines to &DE82.
+
+************** exit routine
+DE82 PLA ;restore registers
+DE83 TAY ;
+DE84 PLA ;
+DE85 TAX ;
+DE86 PLA ;
+DE87 STA &FC ;store A
+
+* IRQ2V default entry *
+
+DE89 LDA &FC ;get back original value of A
+DE8B RTI ;and return to calling routine.
+
+NEXT WEEK: OSBYTE entry.
+
+BBC 6502 Machine Code
+Part Seventeen: The BBC Operating System
+----------------------------------------
+We've been examining the BBC operating system in some detail over the
+last few weeks. Unfortunately the demise of Micronet means that we
+cannot finish completely, as we hoped. So we've put together the next
+twenty weeks' articles in the form of a completely commented
+disassembly of OS 1.20.
+
+This is an excellent example of BBC programming and is full of tips.
+
+Just to remind you of the main points of the software. Entry points
+are pointed to by a jump table in the last six bytes of the ROM.
+
+The font characters are located from &C000 to &C2FF.
+
+OK, so here it is all commented and ready for you to peruse.
+
+Ed says: I have uploaded the series of disassembly articles as ten
+ short TSW files. Look on Micronet on 700100239 (before it's
+ too late!)
+
+ *********** THE END **********
+