![]() | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Learn Multi platform 6502 Assembly Programming... For Monsters! Hello World Series | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
![]() |
Getting Hello World to the
screen isn't much, but it's a vital step! Once we can get a program
running, we can develop it into something much better. In our Bitmap Series, we went directly to the graphics hardware and used our own font, but We've used the firmware in this example for speed. |
Running our Program
We need to compile our program using
VASM... we need to specify some command switches![]() We need to specify a ASM file to build We need to specify an output file, and that we need it to be Binary... We're specifying some Symbols we want defined on the command line... you probably don't need these We're also outputting a listing file ... this is for debugging. We're also disabling Case sensitivity, and telling VASM to check our labels don't look like commands (Usually because we've missed a tab!) |
|
| Once we've built our binary, we need to get it into a disk to run
on the bbc, we use BBCIM
to do this First we add our $.Boot file to the disk (the name is important!) Next we set the disk to autoboot. |
|
| We can use the command line to start the disk image with BeebEm |
|
Debugging Tools

|
Lesson
H2 - Hello World on the C64 Lets learn how to show a Hello World message on the C64... we'll learn how to build our example as a PRG and an CRT Cartridge |
![]() |
![]() C64_HelloWorld.asm
|
|
![]() |
Showing Hello World to the screen
Upper and Lower case fonts
Building a PRG file with Vasm
I use VASM to compile the ASM file into a
usable PRG![]() We have to specify a Source ASM file. We need to tell VASM we want to create a BINary that's a PRG file We need to specify the Destination file name We include some symbols (some of my code uses these - you won't need them) We're specifying an output Listing file We're also disabling case sensitivity, and telling VASM to check our labels don't look like commands (in case we forgot a tab on one of our commands) |
|
| We can start the VICE emulator with the PRG from the command line | ![]() |
Converting to a cartridge
| Running from a
cartridge may make things easier, as our program will no longer be
running from low memory (0-$3FFF).. This area is used by the screen hardware,so it's 'premium' storage space! |
![]() |
Debugging Tools

Showing Hello World to the screen
Building a PRG file with Vasm
I use VASM to compile the ASM file into a
usable PRG![]() We have to specify a Source ASM file. We need to tell VASM we want to create a BINary that's a PRG file We need to specify the Destination file name We include some symbols (some of my code uses these - you won't need them) We're specifying an output Listing file We're also disabling case sensitivity, and telling VASM to check our labels don't look like commands (in case we forgot a tab on one of our commands) |
|
| We can start the VICE emulator with the PRG from the command line | ![]() |
Converting to a cartridge
| The VIC has very
little RAM, so using cartridges will make things a lot easier, and
is something you'll almost certainly want to do, unless your
program is very small and simple. Grime 6502 was too big for a PRG, and that was tiny! |
![]() |
Debugging Tools

Setting up the Cartridge and initializing the screen.
Showing Hello World to the screen
Building and running our cartridge
I compile the code with VASM in a batch
file.![]() We have to specify a Source ASM file. We need to tell VASM we want to create a BINary that's a PRG file We need to specify the Destination file name We include some symbols (You'll need BuildA80 if you're building for Atari 800) We're specifying an output Listing file We're also disabling case sensitivity, and telling VASM to check our labels don't look like commands (in case we forgot a tab on one of our commands) |
|
| We can start the cartridge with the emulator of our choice. | ![]() ![]() |
Debugging Tools
![]() |
The 5200 and
800 are almost the same system - the only reason they don't work
the same is so people couldn't buy console games for the home
computer - the whole decision was a big evil scheme by the accountants ! What can I say... Whoever came up with the idea of moving the GTIA, they deserve a slow painful death!! |

Showing Hello World on the Apple II
Building our program onto a Disk on the Apple II
I build my files with VASM via a batch
file.![]() We have to specify a Source ASM file. We need to tell VASM we want to create a BINary file We need to specify the Destination file name We include some symbols We're specifying an output Listing file We're also disabling case sensitivity, and telling VASM to check our labels don't look like commands (in case we forgot a tab on one of our commands) The Apple II has a 65c02 CPU - to enable the extra features we use the -c02 switch |
|
| We're going to start with a template blank disk,
we'll add our file to it To add the file to our disk, We use the A2In function of A2Tools Finally we'll start our AppleWin emulator with the Disk image - we'll also use a save state to speed things up (so we don't need to type the BRUN command) |
![]() |
Debugging Tools
| We've got some text to the screen without too
much difficulty, We've covered bitmap fonts in the Platform
specific series... Next time in the Simple series, we'll learn how
to get bitmaps to the screen. |
![]() |

Starting a Lynx Cartridge
Drawing a character to the screen
Printing a string to screen
Building an unencrypted cartridge
![]() |
Real Atari Lynx cartridges
need to be encrypted, but we would need a proper OS ROM to run them
(Which cannot legally be distributed!) For our purposes these unencrypted .O files will work just fine! |
Debugging Tools

Starting a Nes or Famicom Cartridge
Waiting for Vblank
Getting A Character to the screen
Printing a string to screen
| Because we're
waiting for VBlank each write, the text will be rather slow, It's enough for this beginner series, but we need a buffer for real games... we covered this in the Platform Specific series |
![]() |
Building our NES cartridge
I build my files with VASM via a batch
file.![]() We have to specify a Source ASM file. We need to tell VASM we want to create a BINary file We need to specify the Destination file name We include some symbols We're specifying an output Listing file We're also disabling case sensitivity, and telling VASM to check our labels don't look like commands (in case we forgot a tab on one of our commands) |
|
| Once we've compiled our cartridge, we can load it with our emulator. | ![]() |
Debugging Tools

Starting a SNES/SFC Cartridge
| We may be able to skip the clear screen part
on some emulators, but emulators like Mesen-S will fill the ram
with random data on power-up to force us to do things properly!...
how cheeky! |
![]() |
Waiting for Vblank
Getting A Character to the screen
Printing a string to screen
Building a SNES / Super Famicom Cartridge
I build my files with VASM via a batch
file.![]() We have to specify a Source ASM file. We need to tell VASM we want to create a BINary file We need to specify the Destination file name We include some symbols We're specifying an output Listing file We're also disabling case sensitivity, and telling VASM to check our labels don't look like commands (in case we forgot a tab on one of our commands) The SNES has a 65c02 CPU - to enable the extra features we use the -c02 switch |
|
| Once we've compiled our cartridge, we can load it with our emulator. | ![]() |
Debugging Tools

Starting a PC Engine/TurboGrafx-16 Card
| The PC Engine
has lots of special commands... most important for us here are ST0
, ST1 and ST2... these save fixed values to the graphics hardware,
and are equivalent to STA $0100, STA $0102 and STA $0103 ST0 Selects a register, and ST1/2 save values to that register... Register 0 is the 'address select' register... Register 2 is Data write - sending data to the address selected with Register 0 It may sound confusing, but don't worry too much if you don't understand it yet - just copy the code here for now. |
![]() |
Getting A Character to the screen
Printing a string to screen
Building a PC Engine/TurboGrafx-16 Card
I build my files with VASM via a batch
file.![]() We have to specify a Source ASM file. We need to tell VASM we want to create a BINary file We need to specify the Destination file name We include some symbols We're specifying an output Listing file We're also disabling case sensitivity, and telling VASM to check our labels don't look like commands (in case we forgot a tab on one of our commands) We need to be able to use the 6280 exclusive opcodes - to enable the extra features we use the -6280 switch |
|
| Once we've compiled our cartridge, we can load it with our emulator. | ![]() |
Debugging Tools

Showing Hello World to the screen
Building a PRG file with Vasm
I use VASM to compile the ASM file into a
usable PRG![]() We have to specify a Source ASM file. We need to tell VASM we want to create a BINary that's a PRG file We need to specify the Destination file name We include some symbols (some of my code uses these - you won't need them) We're specifying an output Listing file We're also disabling case sensitivity, and telling VASM to check our labels don't look like commands (in case we forgot a tab on one of our commands) |
|
| We can start the VICE emulator with the PRG from the command line | ![]() |
Debugging Tools

![]() |
Unlike most
BASICs, BBC BASIC is CASE SENSITIVE, so you need to put all the
commands in CAPS! Surprisingly it seems the assembler is NOT!... but we'll put the commands in CAPS there too! |
The Basic wrapper
| Before we do anything, lets change our screen mode! The default mode will work OK, but some of the characters will show differently, so lets switch to MODE 0, so [ ] and a few others show right! |
![]() |
| Lets look at a simple wrapper for a minimal ASM program (A RTS
Statement!) :REM - A basic REM comment statement \ - an Assembly comment (; also works) [ ] - Start and end of the ASM block DIM MC% 100 - This Defines a block of 101 bytes from free memory and calls it MC% FOR opt%=0 TO 3 STEP 3 - This runs two passes of our assembly file, once with option 0, and once with option 3 P%=MC% - This sets the program counter (P%) for the start of the pass OPT opt% - This is an assembler directive, and tells the assembler what OPTions to use for the pass |
![]() |
| We can type all of that in if we really want, but we can just copy paste it from notepad, and let the emulator do all the work! | ![]() |
| To assemble our program we just use RUN We can start our program with CALL MC% , or by calling the address we assembled to (CALL 6681) |
![]() |
Showing Hello World to the screen
| We're going to convert our previous hello world example to BBC
BASIC format. The main changes are: Hexadecimal needs to be specified with & prefix Labels need to be prefixed with . (full stop) DIV used to get the top byte of and address MOD used to get the bottom byte of an address Bytes and Strings need to be defined with EQU |
![]() |
| We're going to use the firmware function &FFE3
to print characters (known as OSASCI) We'll also use &FFE7 to start a new line (known as OSNEWL) We're going to 'extend' this to make a PrintString routine... We'll use Zeropage pair $70/1 to store an address which will point to a string in memory... We use Y as an offset to the start address, and We'll print characters to the screen, until we get a character 255... |
![]() |
| We need to load the High and Low bytes of our address into the
$20/1 zero page entries to define the address of our string, and
then call our PrintString function - this will show our string to
the screen. We get the high part with DIV 256, and the low part with MOD 256 (Remainder of division) |
![]() |
| We need to define our string! We define a string with EQUS, and a byte with EQUB |
![]() |
| We start our program with CALL
MC% Our Hello World message will be shown to screen |
![]() |

|
Lesson
H12 - 'Hello Chibiko' on the Atari 2600 (Nearly hello world!) Lets take a look at the Apple 2600. We'll use the Playfield background to show a full screen 40x48 bitmap. |
![]() |
![]() A26_HelloChibiko.asm
|
![]() |
![]() |
The Apple 2600
doesn't really have a font or characters, we have to draw our
screen image using the playfiled in 2 strips of 20 pixels. We COULD use this to show hello world, but it will be more useful to show an amazing full screen image of our choosing... ME! |
About the playfield
| The Playfield data is controlled by 3 registers for a total of 20
bits. The top 4 bits of $0D (PF0 - Right to left) are first, then $0E (PF1 - Left to right), finally $0F (PF2 - Right to left) The bits of PF1 are in the opposite order to PF0 and PF2 The 3 Registers are repeated on the right hand side of the screen, but we mirror them instead, by setting bit 0 of $0A (CTRLPF) These will just repeat down the screen, unless we change them at the exact time the raster beam is drawing that line of the screen! |
Normal:![]() Mirrored: ![]() Here we set PF0 PF1 PF2 to |%00110000 %10111001 %01011111 |
| Its tricky, but if If we time
things right and change the 3 registers mid screen, we can
effectively give ourselves a 40 pixel screen... just enough to draw
our Chibiko mascot. We also change the playfield forground color... Reg $08 - COLUPF We could change the bacground color with reg $09 COLUBK. Both take a color in the format %CCCCLLLL - where C is the color and L is the luminescence. |
![]() |
| If we set bit 1 of the Playfield control register ($0A CTRLPF) we
can set the playfield to use the colors for Player 0 and 1 on the
left and right. We set these with registers $06 (COLUP0) and $07 (COLUP1) |
|
The screen!
The graphics registers on the Atari 2600 don't change themselves, so we
need to time our code correctly for each line of the screen, we also need
to send the signals to the screen for Vblank and Vsync.
Overscan is the offscreen area we can't draw to.
We need to draw the screen line by line. Each line takes 76 cpu ticks.
We can get the hardware to pause the CPU until a line ends by writing any value to $02 (WSYNC) - We'll probably want to do this during the drawn screen
Alternatively we can set the timer with $296 (TIM64T) and wait until bit 7 of $285 (INSTAT) becomes 1 - We'll do this during Vblank/overscan so we can worry about our game logic without counting lines.
Alternatively if we're super hard core, we can look up all the instruction times of the CPU and ensure our code takes 76 ticks!
Bit 1 of $00 (VSYNC) defines the start/end of
vsync
Bit 1 of $01 (VBLANK) defines the start/end of vblank
We don't need to do anything for overscan, except calculate the time it
takes.
Showing our Chibiko!
| At the end of our cartridge ($FFFC) we need to define a footer,
which has the reset jump to the start of our program. Our program starts at $F000 |
![]() ![]() |
| First we'll set up our playfield with register $0A (CTRLPF) Bit 0 defines if the screen is mirrored or not. Bit 1 turns on 'Score mode', which uses the player colors for the Left/Right of the screen. |
![]() |
| Here is our bitmap data. Each half of the screen uses 3 bytes for PF0 PF1 and PF2, and one color byte. This means each line is 4 bytes. We don't need to use both color bytes if we don't want! |
![]() ![]() |
| At the start of our frame, we need to begin VSYNC. We then need to wait 3 lines with WSYNC by writing anything to $02 after Vsync, we'll do Vblank, this lasts about 43 TIM64T interrupts, so we'll set the timer and do the tasks for our game/program! |
![]() |
| Before the draw of the screen, we want to reset everything so
nothing draws onscreen before we're ready. We clear all the drawing registers, and set all the colors to black. |
![]() |
| We use 'WaitTimer' to pause until the TIM64T count reaches zero, we then execute a WSYNC so we're exactly timed to a line. | ![]() |
| For each line of the screen we need to do the various tasks to
update the screen. Here we're setting PF0, PF1 and PF2 and maybe some colors. We use Y to count the lines, and X as an offset to the bitmap data. PF0 on the left is drawn almost immediately after WSYNC, and we need to ensure the right hand part is updated after the left hand part has drawn, for this reason the order of update is: PF1l pf2l PF0r PF1r colors PF2r PF0l |
![]() |
| After the screen, we need to wait for the overscan part... this
would be another great time to do some game tasks! We're done, so we repeat for the next frame! |
![]() |

| View Options |
| Default Dark |
| Simple (Hide this menu) |
| Print Mode (white background) |
| Top Menu |
| ***Main Menu*** |
| Youtube channel |
| Patreon |
| Introduction to Assembly (Basics for absolute beginners) |
| Amazon Affiliate Link |
| AkuSprite Editor |
| ChibiTracker |
| Dec/Bin/Hex/Oct/Ascii Table |
| Alt Tech |
| Archive.org |
| Bitchute |
| Odysee |
| Rumble |
| DailyMotion |
| Please note: I wlll upload more content to these alt platforms based on the views they bring in |
| 68000 Content |
| ***68000 Tutorial List*** |
| Learn 68000 Assembly |
| Hello World Series |
| Platform Specific Series |
| Simple Samples |
| Grime 68000 |
| 68000 Downloads |
| 68000 Cheatsheet |
| Sources.7z |
| DevTools kit |
| 68000 Platforms |
| Amiga 500 |
| Atari ST |
| Neo Geo |
| Sega Genesis / Mega Drive |
| Sinclair QL |
| X68000 (Sharp x68k) |
| 8086 Content |
| Learn 8086 Assembly |
| Platform Specific Series |
| Hello World Series |
| Simple Samples |
| 8086 Downloads |
| 8086 Cheatsheet |
| Sources.7z |
| DevTools kit |
| 8086 Platforms |
| Wonderswan |
| MsDos |
| ARM Content |
| Learn ARM Assembly |
| Learn ARM Thumb Assembly |
| Platform Specific Series |
| Hello World |
| Simple Samples |
| ARM Downloads |
| ARM Cheatsheet |
| Sources.7z |
| DevTools kit |
| ARM Platforms |
| Gameboy Advance |
| Nintendo DS |
| Risc Os |
| Risc-V Content |
| Learn Risc-V Assembly |
| Risc-V Downloads |
| Risc-V Cheatsheet |
| Sources.7z |
| DevTools kit |
| MIPS Content |
| Learn Risc-V Assembly |
| Platform Specific Series |
| Hello World |
| Simple Samples |
| MIPS Downloads |
| MIPS Cheatsheet |
| Sources.7z |
| DevTools kit |
| MIPS Platforms |
| Playstation |
| N64 |
| PDP-11 Content |
| Learn PDP-11 Assembly |
| Platform Specific Series |
| Simple Samples |
| PDP-11 Downloads |
| PDP-11 Cheatsheet |
| Sources.7z |
| DevTools kit |
| PDP-11 Platforms |
| PDP-11 |
| UKNC |
| TMS9900 Content |
| Learn TMS9900 Assembly |
| Platform Specific Series |
| Hello World |
| TMS9900 Downloads |
| TMS9900 Cheatsheet |
| Sources.7z |
| DevTools kit |
| TMS9900 Platforms |
| Ti 99 |
| 6809 Content |
| Learn 6809 Assembly |
| Learn 6309 Assembly |
| Platform Specific Series |
| Hello World Series |
| Simple Samples |
| 6809 Downloads |
| 6809/6309 Cheatsheet |
| Sources.7z |
| DevTools kit |
| 6809 Platforms |
| Dragon 32/Tandy Coco |
| Fujitsu FM7 |
| TRS-80 Coco 3 |
| Vectrex |
| 65816 Content |
| Learn 65816 Assembly |
| Hello World |
| Simple Samples |
| 65816 Downloads |
| 65816 Cheatsheet |
| Sources.7z |
| DevTools kit |
| 65816 Platforms |
| SNES |
| eZ80 Content |
| Learn eZ80 Assembly |
| Platform Specific Series |
| eZ80 Downloads |
| eZ80 Cheatsheet |
| Sources.7z |
| DevTools kit |
| eZ80 Platforms |
| Ti84 PCE |
| IBM370 Content |
| Learn IBM370 Assembly |
| Simple Samples |
| IBM370 Downloads |
| IBM370 Cheatsheet |
| Sources.7z |
| DevTools kit |
| Super-H Content |
| Learn SH2 Assembly |
| Hello World Series |
| Simple Samples |
| SH2 Downloads |
| SH2 Cheatsheet |
| Sources.7z |
| DevTools kit |
| SH2 Platforms |
| 32x |
| Saturn |
| PowerPC Content |
| Learn PowerPC Assembly |
| Hello World Series |
| Simple Samples |
| PowerPC Downloads |
| PowerPC Cheatsheet |
| Sources.7z |
| DevTools kit |
| PowerPC Platforms |
| Gamecube |
| Work in Progress |
| ChibiAndroids |
| Misc bits |
| Ruby programming |








