Category Archives: 6502

BBC Micro 6502 Assembly: Simple Square Program

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:

  1. Converts to absolute screen coordinates
  2. Issues a PLOT 85, x, y command (or similar PLOT code)
  3. This PLOT command then generates a sequence of VDU commands

The similarity works like this:

DRAWPLOTVDU 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.