
As promised, the “much anticipated” follow-up to ‘Hello World‘ in assembly. I’m trying to pick simple topics to show how this works so I make no apologies for the somewhat bland output, in this case, a square. I did make it a yellow square though.
Again, this is all written with the BBC Micro assembler so you will see hexadecimal notation indicated with an & instead of a $ like you may see in other assemblers.
Before we dive in, I need to describe how commands Plot, Draw and VDU work on the BBC. The BBC Micro’s DRAW command in BASIC is actually implemented using the same VDU command system as PLOT.
When you use DRAW x,y in BASIC, it internally:
- Converts to absolute screen coordinates
- Issues a
PLOT 85, x, ycommand (or similar PLOT code) - This PLOT command then generates a sequence of VDU commands
The similarity works like this:
DRAW → PLOT → VDU sequence
For example, PLOT 85, x, y (draw absolute line) becomes something like:
VDU 25, 85, x MOD 256, x DIV 256, y MOD 256, y DIV 256
So all three commands (DRAW, PLOT, VDU) are essentially layers of the same system:
- VDU is the lowest level – sends bytes directly to the VDU driver
- PLOT is a mid-level wrapper that formats graphics commands into VDU sequences (VDU 25 specifically)
- DRAW is a high-level BASIC convenience command that translates to PLOT commands
This layered approach meant the 6502 assembly implementation could reuse the same VDU driver code for all graphics operations, with BASIC commands simply being syntactic sugar that is ultimately funneled down to VDU byte sequences.
Straight into the code. Don’t be scared off by the length – this makes it easier to understand.
10 REM BBC Micro 6502 Assembly Program to Draw a Square
20 REM Uses OS graphics routines to draw a square on screen
30 REM Type RUN to execute
40
50 oswrch=&FFEE
60
70 FOR pass=0 TO 2 STEP 2
80 P%=&1000
90 [
100 OPT pass
110
120 .start
130 LDA #22 ; VDU 22 - set screen mode
140 JSR oswrch
150 LDA #1 ; Mode 1
160 JSR oswrch
170
180 LDA #16 ; VDU 16 - clear graphics area
190 JSR oswrch
200
210 LDA #29 ; VDU 29 - set graphics origin
220 JSR oswrch
230 LDA #0 ; X origin (low byte)
240 JSR oswrch
250 LDA #2; X origin (high byte)
260 JSR oswrch
270 LDA #0 ; Y origin (low byte)
280 JSR oswrch
290 LDA #2; Y origin (high byte)
300 JSR oswrch
310
320 LDA #18 ; VDU 18 - set graphics color
330 JSR oswrch
340 LDA #0; GCOL action (normal plotting)
350 JSR oswrch
360 LDA #2; Color 2 (Yellow in mode 1)
370 JSR oswrch
380
390 LDA #25 ; VDU 25 - PLOT command
400 JSR oswrch
410 LDA #4; PLOT 4 - move to absolute coordinates
420 JSR oswrch
430 LDA #&CE ; X = -50 (low byte)
440 JSR oswrch
450 LDA #&FF ; X = -50 (high byte)
460 JSR oswrch
470 LDA #200 ; Y = 50 (low byte)
480 JSR oswrch
490 LDA #0; Y = 50 (high byte)
500 JSR oswrch
510
520 LDA #25 ; VDU 25 - PLOT command
530 JSR oswrch
540 LDA #5; PLOT 5 - draw line to absolute coordinates
550 JSR oswrch
560 LDA #200 ; X = 50 (low byte)
570 JSR oswrch
580 LDA #0; X = 50 (high byte)
590 JSR oswrch
600 LDA #200 ; Y = 50 (low byte)
610 JSR oswrch
620 LDA #0; Y = 50 (high byte)
630 JSR oswrch
640
650 LDA #25 ; VDU 25 - PLOT command
660 JSR oswrch
670 LDA #5 ; PLOT 5 - draw line to absolute coordinates
680 JSR oswrch
690 LDA #200 ; X = 50 (low byte)
700 JSR oswrch
710 LDA #0; X = 50 (high byte)
720 JSR oswrch
730 LDA #&CE ; Y = -50 (low byte)
740 JSR oswrch
750 LDA #&FF ; Y = -50 (high byte)
760 JSR oswrch
770
780 LDA #25 ; VDU 25 - PLOT command
790 JSR oswrch
800 LDA #5; PLOT 5 - draw line to absolute coordinates
810 JSR oswrch
820 LDA #&CE ; X = -50 (low byte)
830 JSR oswrch
840 LDA #&FF ; X = -50 (high byte)
850 JSR oswrch
860 LDA #&CE ; Y = -50 (low byte)
870 JSR oswrch
880 LDA #&FF ; Y = -50 (high byte)
890 JSR oswrch
900
910 LDA #25 ; VDU 25 - PLOT command
920 JSR oswrch
930 LDA #5; PLOT 5 - draw line to absolute coordinates
940 JSR oswrch
950 LDA #&CE ; X = -50 (low byte)
960 JSR oswrch
970 LDA #&FF ; X = -50 (high byte)
980 JSR oswrch
990 LDA #200 ; Y = 50 (low byte)
1000 JSR oswrch
1010 LDA #0; Y = 50 (high byte)
1020 JSR oswrch
1030 RTS
1120 ]
1130 NEXT pass
1170 CALL &1000
FURTHER EXPLANATION:
Hopefully the explanation on how it is working in a similar fashion to BASIC’s VDU command above helps describe how the line is drawn.
You will notice we call the OS Write Character routine after each change. This essentially tells the OS we are writing to the screen.
We have the concept of ‘low byte’ and ‘high byte’ because we are talking about an 8-bit system which can’t handle numbers greater than 255 (0-255). Since the mode 1 screen is 320 pixels this is obviously higher than 255. In this case, low byte refers to 1-127 when we consider it as binary (11111111 = 256 dec) and high byte is the next byte along starting at 5.
As with anything, best to test for yourself. I do most of my testing/playing using the excellent BeebEm. There are probably (almost certainly) better ways to accomplish this so feel free to post any comments with improvements. I don’t pretend to be an expert here by any stretch, merely trying to explain how BASIC maps to machine language for simple tasks.