Blog 2021/6/5
<- previous | index | next ->
When it comes to learning a new language / platform / concept / etc in programming, being forced to solve problems (that is, being engaged) is far more effective than passively reading docs or watching tutorials.
Some good examples of this approach:
- The 4clojure website.
- The Little Schemer by Friedman and Felleisen
Another name for this learning approach is the code kata.
Here are some katas I've come up with for learning 6502 assembly, using the Easy6502 simulator. Paste in each solution, then click "Assemble", then click "Run".
The Easy6502 machine comes with these notes:
Notes:
Memory location $fe contains a new random byte on every instruction.
Memory location $ff contains the ascii code of the last key pressed.
Memory locations $200 to $5ff map to the screen pixels. Different values will
draw different colour pixels. The colours are:
$0: Black
$1: White
$2: Red
$3: Cyan
$4: Purple
$5: Green
$6: Blue
$7: Yellow
$8: Orange
$9: Brown
$a: Light red
$b: Dark grey
$c: Grey
$d: Light green
$e: Light blue
$f: Light grey
Some additional 6502 resources:
- http://www.6502.org/tutorials/6502opcodes.html
- https://www.atariarchives.org/roots/chapter_6.php
- http://www.obelisk.me.uk/6502/addressing.html
LDA #1 ; load an immediate (decimal 1) into the accumulator.
STA $0200 ; store the accumlator to memory location 0x0200.
BRK ; done.
LDA #3 ; load an immediate (decimal 3) into the accumulator.
STA $05ff ; store the accumlator to memory location 0x05FF.
BRK ; done.
The linear approach, using decimal values:
LDA #0 ; black
STA 512 ; pixel (0,0)
LDA #1 ; white
STA 513 ; pixel (0,1)
LDA #2 ; red
STA 514 ; pixel (0,2)
LDA #3
STA 516
LDA #4
STA 517
LDA #5
STA 518
LDA #6
STA 519
LDA #7
STA 520
LDA #8
STA 521
LDA #9
STA 522
LDA #10
STA 523
LDA #11
STA 524
LDA #12
STA 525
LDA #13
STA 526
LDA #14
STA 527
LDA #15
STA 528
BRK
The linear approach, using hex values:
LDA #$0 ; black
STA $0200 ; pixel (0,0)
LDA #$1 ; white
STA $0201 ; pixel (0,1)
LDA #$2 ; red
STA $0202 ; pixel (0,2)
LDA #$3
STA $0203
LDA #$4
STA $0204
LDA #$5
STA $0205
LDA #$6
STA $0206
LDA #$7
STA $0207
LDA #$8
STA $0208
LDA #$9
STA $0209
LDA #$A
STA $020A
LDA #$B
STA $020B
LDA #$C
STA $020C
LDA #$D
STA $020D
LDA #$E
STA $020E
LDA #$F
STA $020F
BRK
Using a loop:
LDA #0 ; use the accumulator to store the color.
LDX #0 ; use X to store the pixel index.
STA $0200,X ; write the first pixel at (0,0).
loop:
ADC #1 ; increment the color.
INX ; increment the pixel index.
STA $0200,X ; write the pixel
CPX #15 ; if X != 15, loop.
BNE loop
BRK ; else, done.
LDA #2 ; red
LDX #0 ; pixel offset
STA $0200,X
loop:
INX
STA $0200,X
CPX #31 ; if X != 31, loop.
BNE loop
BRK ; else, done.
Because pixel index wraps to the next line automatically, we can reuse the previous solution but count up to 255 instead of 31:
LDA #4
LDX #0
STA $0200,X
loop:
INX
STA $0200,X
CPX #255
BNE loop
BRK
This is a bit trickier because we need to write 1024 pixels, but the registers can only count up to 255.
Our first approach might be to simply use four copies of the previous solution, with each one starting on a different "page" of memory:
LDA #5 ; green
; fill pixels 0x0200 through 0x02FF
LDX #0
STA $0200,X
loop1:
INX
STA $0200,X
CPX #$FF
BNE loop1
; fill pixels 0x0300 through 0x03FF
LDX #0
STA $0300,X
loop2:
INX
STA $0300,X
CPX #$FF
BNE loop2
; fill pixels 0x0400 through 0x04FF
LDX #0
STA $0400,X
loop3:
INX
STA $0400,X
CPX #$FF
BNE loop3
; fill pixels 0x0500 through 0x05FF
LDX #0
STA $0500,X
loop4:
INX
STA $0500,X
CPX #$FF
BNE loop4
BRK
If we use indirect indexed addressing, we can store the page number in memory and repeat the inner loop four times:
LDA #5 ; green
; store the value 0x0200 starting at address 0x0000.
LDX #$00
STX $0
LDX #$02
STX $1
; the inner loop: write 8 lines of pixels.
LDY #0
STA ($0),Y
loop:
INY
STA ($0),Y
CPY #$FF
BNE loop
; the outer loop: increment the pixel page and restart the inner loop.
LDX $1
INX
STX $1
CPX #6 ; repeat the inner loop for pages 3, 4, and 5.
BNE loop
BRK