Skip to content

Commit

Permalink
Add screen04 lesson (#12)
Browse files Browse the repository at this point in the history
  • Loading branch information
mauri870 authored Jul 22, 2018
1 parent 63a2401 commit 53e7efb
Show file tree
Hide file tree
Showing 12 changed files with 827 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/screen04/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# SCREEN04 - How to manipulate strings

The SCREEN04 lesson builds on top of SCREEN03 teaching how to manipulate strings, implement division and print formatted strings.
16 changes: 16 additions & 0 deletions src/screen04/counter.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
@;
@; Counter functions to be used by this exercise
@;

.section .text
.global delay
delay:
ldr r1, =0x3F000000 @; pi peripheral address
orr r1, r1, #0x3000 @; r1 = r1 | 0x3000 = 0x3F003000 timer base address
ldr r2, [r1, #0x4] @; time in microseconds given by the timer
delay1$:
ldr r3, [r1, #0x4] @; get timer in microseconds in each iteration
sub r3, r3, r2 @; current timer - initial timer
cmp r3, r0 @; compare time elapsed with desired timer
blt delay1$ @; if elapsed time < desired time repeat the loop
mov pc, lr @; return
251 changes: 251 additions & 0 deletions src/screen04/drawing.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
@;
@; Functions to draw on the screen
@;

.section .text
.global DrawPixel
DrawPixel:
px .req r0
py .req r1
addr .req r2

ldr addr, =graphicsAddress @; load address into r2
ldr addr, [addr] @; load the value into r2

height .req r3
ldr height, [addr, #4] @; load the height into r3
sub height, #1 @; subtract 1 from height
cmp py, height @; cmp py with the actual height
movhi pc, lr @; return if higher
.unreq height

width .req r3
ldr width, [addr, #0] @; load the width into r3
sub width, #1 @; subtract 1 from width
cmp px, width @; cmp py with the actual width
movhi pc, lr @; return if higher

ldr addr, [addr, #32] @; get the gpu pointer for the framebuffer response
and addr, #0x3FFFFFFF @; convert bus address to physical address used by the ARM CPU

add width, #1 @; add 1 to r3
mla px, py, width, px @; multiply px with width, adds px and store the least significant 32 bits into px
.unreq width
.unreq py
add addr, px, lsl #1 @; adds px and addr and left shift by 1
.unreq px
fore .req r3
ldr fore, =foreColor @; load forecolor address into r3
ldrh fore, [fore] @; load half word from fore into r3

strh fore, [addr] @; store half word from fore into gpu framebuffer pointer
.unreq fore
.unreq addr
mov pc, lr @; return

.global DrawLine
DrawLine:
push {r4,r5,r6,r7,r8,r9,r10,r11,r12,lr} @; push caller-saved registers and lr
x0 .req r9
x1 .req r10
y0 .req r11
y1 .req r12

mov x0, r0 @; move function args into registers
mov x1, r2
mov y0, r1
mov y1, r3

dx .req r4
dyn .req r5 @; delta y negative stored for speed
sx .req r6
sy .req r7
err .req r8

cmp x0, x1 @; compare x0 and x1
subgt dx, x0, x1 @; if x0 greater than x1 subtract and store into dx
movgt sx, #-1 @; if x0 greater than x1 move -1 to step x
suble dx, x1, x0 @; if x0 less than or equal x1 subtract and store into dx
movle sx, #1 @; if x0 less than or equal x1 move 1 into step x

cmp y0, y1
subgt dyn, y1, y0
movgt sy, #-1
suble dyn, y0, y1
movle sy, #1

add err, dx, dyn
add x1, sx
add y1, sy

pixelLoop$:
teq x0, x1
teqne y0, y1
popeq {r4,r5,r6,r7,r8,r9,r10,r11,r12,pc}

mov r0, x0
mov r1, y0
bl DrawPixel

cmp dyn, err, lsl #1
addle err, dyn
addle x0, sx

cmp dx, err, lsl #1
addge err, dx
addge y0, sy

b pixelLoop$

.unreq x0
.unreq x1
.unreq y0
.unreq y1
.unreq dx
.unreq dyn
.unreq sx
.unreq sy
.unreq err

.global DrawCharacter
DrawCharacter:
cmp r0, #127 @; check if is a valid ascII code
movhi r0, #0
movhi pc, lr

push {r4, r5, r6, r7, r8, lr}
x .req r4
y .req r5
addr .req r6
mov x, r1
mov y, r2
ldr addr, =font
add addr, r0, lsl #4

lineLoop$:
bits .req r7
bit .req r8
ldrb bits, [addr]
mov bit, #8

charPixelLoop$:
subs bit, #1
blt charPixelLoopEnd$
lsl bits, #1
tst bits, #0x100
beq charPixelLoop$

add r0, x, bit
mov r1, y
bl DrawPixel

teq bit, #0
bne charPixelLoop$
charPixelLoopEnd$:
.unreq bit
.unreq bits
add y, #1
add addr, #1
tst addr, #0b1111
bne lineLoop$

.unreq x
.unreq y
.unreq addr

width .req r0
height .req r1
mov width, #8
mov height, #16

pop {r4,r5,r6,r7,r8,pc}
.unreq width
.unreq height

.global DrawString
DrawString:
x .req r4
y .req r5
x0 .req r6
string .req r7
length .req r8
char .req r9
push {r4, r5, r6, r7, r8, r9, lr}

mov string, r0
mov x, r2
mov x0, x
mov y, r3
mov length, r1

stringLoop$:
subs length, #1
blt stringLoopEnd$

ldrb char, [string]
add string, #1

mov r0, char
mov r1, x
mov r2, y
bl DrawCharacter
cwidth .req r0
cheight .req r1

teq char, #'\n'
moveq x, x0
addeq y, cheight
beq stringLoop$

teq char, #'\t'
addne x, cwidth
bne stringLoop$

add cwidth, cwidth, lsl #2
x1 .req r1
mov x1, x0

stringLoopTab$:
add x1, cwidth
cmp x, x1
bge stringLoopTab$
mov x, x1
.unreq x1
b stringLoop$
stringLoopEnd$:
.unreq cwidth
.unreq cheight

pop {r4, r5, r6, r7, r8, r9, pc}
.unreq x
.unreq y
.unreq x0
.unreq string
.unreq length

.global SetForeColor
SetForeColor:
cmp r0, #0x10000 @; compare color to max integer
movhs pc, lr @; return according to cmp flags (higher or same)
ldr r1, =foreColor @; load forecolor into register r1
strh r0, [r1] @; store half word from r0 into r1
mov pc, lr @; return

.global SetGraphicsAddress
SetGraphicsAddress:
ldr r1, =graphicsAddress @; load graphics address into r1
str r0, [r1] @; store r0 into r1
mov pc, lr @; return

.section .data
.align 1
foreColor:
.hword 0xFFFF @; half word with the forecolor (white)

.align 2
graphicsAddress:
.int 0 @; graphics address (default 0)

.align 4
font:
.incbin "font.bin" @; the bitmap font to use
Binary file added src/screen04/font.bin
Binary file not shown.
74 changes: 74 additions & 0 deletions src/screen04/framebuffer.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
@;
@; Functions to define framebuffers to interact with the GPU
@;

.section .text
.global InitializeFrameBuffer
InitializeFrameBuffer:
width .req r0 @; set up alias
height .req r1
bitDepth .req r2

cmp width, #4096 @; compare width with 4096
cmpls height, #4096 @; compare height with 4096 if width is less or equal to 4096
cmpls bitDepth, #32 @; compare bitDepth with 32 if height is less or equal to 4096
result .req r0
movhi result, #0 @; mov 0 to result if last cmp C and Z flag are clear (higher)
movhi pc, lr @; return if last cmp C and Z flag are clear (higher)

push {r4, lr} @; save the address the function should return to

fbInfoAddr .req r4
ldr fbInfoAddr, =FrameBufferInfo @; load frame buffer addr into register
str width, [fbInfoAddr] @; store width into fbInfoAddr offset 0
str height, [fbInfoAddr, #4] @; store height into fbInfoAddr offset 4
str width, [fbInfoAddr, #8] @; store width into fbInfoAddr offset 8
str height, [fbInfoAddr, #12] @; store height into fbInfoAddr offset 12
str bitDepth, [fbInfoAddr, #20] @; store bitDepth into fbInfoAddr offset 20
.unreq width @; unset alias
.unreq height
.unreq bitDepth

mov r1, #0
str r1, [fbInfoAddr, #16] @; reset framebuffer
str r1, [fbInfoAddr, #24]
str r1, [fbInfoAddr, #28]
str r1, [fbInfoAddr, #32]
str r1, [fbInfoAddr, #36]

mov r0, fbInfoAddr
bl FrameBufferWrite @; write message to mailbox
teq result, #0 @; check if last function succeed
movne result, #0 @; if result not equal to 0, set result to 0
popne {r4, pc} @; return if result not equal to 0

mov result, fbInfoAddr @; mov frame buffer info address to r0
.unreq result
.unreq fbInfoAddr
pop {r4, pc} @; return

.global FrameBufferWrite
FrameBufferWrite:
push {lr}
orr r0, #0xC0000000 @; signal the GPU to not flush its cache
mov r1, #1 @; channel for mailbox write
bl MailboxWrite @; write message to mailbox channel 1

mov r0, #1 @; channel for mailbox read
bl MailboxRead @; read the response from mailbox channel 1
pop {pc}

.section .data
.align 4
.global FrameBufferInfo
FrameBufferInfo:
.int 1024 @; #0 Physical Width
.int 768 @; #4 Physical Height
.int 1024 @; #8 Virtual Width
.int 768 @; #12 Virtual Height
.int 0 @; #16 GPU - Pitch
.int 16 @; #20 Bit Depth
.int 0 @; #24 X
.int 0 @; #28 Y
.int 0 @; #32 GPU - Pointer
.int 0 @; #36 GPU - Size
39 changes: 39 additions & 0 deletions src/screen04/led.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
@;
@; Functions to interact with the leds
@;

.section .text
.global SetACTLedState
SetACTLedState:
push {lr} @; save address the function should return to
mov r1, r0 @; move the led state to r1
ldr r0, =message @; load the message into r0
mov r2, #0
str r2, [r0, #4] @; reset request code
str r2, [r0, #16] @; reset request/response size
mov r2, #130
str r2, [r0, #20] @; reset pin number

str r1, [r0, #24] @; overwrite the led state

mov r1, #8 @; set mailbox channel
bl MailboxWrite @; write the message
mov r0, #8 @; the channel to read the message from
bl MailboxRead @; read the message to prevent the FIFO queue to get full
pop {pc} @; return

.section .data
.align 4 @; last 4 bits of the next label set to 0 (16-byte alligned)
message:
.int size @; #0 message header contains the size of the message
.int 0 @; #4 request code 0

.int 0x00038041 @; #8 header tag ID
.int 8 @; #12 size of tag data
.int 0 @; #16 request/response size

.int 130 @; #20 pin number
.int 1 @; #24 pin state
.int 0 @; #28 signal the GPU that the message is over
size:
.int . - message @; size of the message
Loading

0 comments on commit 53e7efb

Please sign in to comment.