获取位图显示 MIPS 中像素的地址
Get address of pixel in bitmap display MIPS
我正在使用 MARS-simulator 的位图显示,单位宽度为 16px,起始地址为 $gp。
我如何使用坐标获取特定像素的地址?
示例 (x,y)
我想我只需要计算像素的数量,直到到达 (x,y) 并将其用作 $gp?
上的偏移量
伪:
>ColAmount = 32 #RowLength
>RowAmount = 16 #ColumnHeight
>x = 4
>y = 5
Coordinate = (x, y)
AmountOfPixelsUntilCoordinate = (RowAmount * y) + ColAmount
offset = AmountOfPixelsUntilCoordinate
addressOfPixel = offset($gp)
这是正确的吗?我如何在 MIPS ASM 中实现它?
您还必须提供显示尺寸。即 16x16 "unit" 和 512x256 "display" 表示实际位图分辨率为 32x16 像素(512/16、256/16)。
那么“index of pixel(x, y)”就是y * 32 + x
=> 你有问题。但是要获得内存 offset,你必须适应单个像素的大小,这需要整个 word
,所以 offset = 4 * index
.
最终内存地址为$gp + offset
。
你几乎答对了,只是少了 *4(当然 *4 不用乘法,但只剩下 2:sll $<offset_reg>, $<index_reg>, 2
)。 (*32
是 "shift left by 5")
编辑:通过 (x, y) 位置跟踪某物的示例(即使使用自定义坐标系,在此示例中 "x" 与从左到右的位图 0..31 相同,但 "y"是从0..15从下到上(位图从上到下是0..15)。
计算内存偏移量和绘制像素到Bitmap的主要部分在评论之后:
# when ball is on the current row, draw it *now* (to minimize flickering)
如何运行它:MARS4.5,验证"Delayed branching"是否关闭,工具->位图显示并将其配置为:16x16 单位,512x256 显示(= 位图大小为 32x16 像素), 基地址为 $gp
。编译,运行.
.data
ball_move_x: .byte -1
ball_move_y: .byte 1
.text
.eqv bounce_pos_y_min 1
.eqv bounce_pos_y_max 14
.eqv bounce_pos_x_min 1
.eqv bounce_pos_x_max 30
.eqv adjust_y_pos_xor 15
.eqv ball_colour 0x00d0e0ff
li $t1, 0x00ff0000 #Loading RED in register
li $t2, 0x00ffff00 #Loading YELLOW in register
li $t3, 3 #"ball" x position
li $t4, 3 #"ball" y position (0->15 from bottom upward!)
li $t5, ball_colour
big_loop:
# top row + first column
move $a0, $gp # pointer to write to
li $a1, 33 # 32 pixels for first row, +1 for left column
move $a2, $t2 # yellow
jal setPixels
# 14 red rows with yellow endings+starts
li $t0, 14
red_rows_loop:
li $a1, 30
move $a2, $t1
jal setPixels # set 30 background pixels in middle
# when ball is on the current row, draw it *now* (to minimize flickering)
bne $t4, $t0, skip_ball_draw
xori $at, $t4, adjust_y_pos_xor # y pos goes from BOTTOM! -> flipping it
# y ($t4) pos goes from bottom to make compare with count-down ($t0) simple
# after flipping it, the $at has here real bitmap Y pos going 0->15 from top
sll $at, $at, 5 # calculate offset in $at: at = y_pos * 32
add $at, $at, $t3 # at = y_pos * 32 + x_pos = "index"
sll $at, $at, 2 # at = (y_pos * 32 + x_pos)*4 = "offset"
add $at, $at, $gp # at = gp + offset
sw $t5, ($at) # draw it!
# W: dont't use $at unless you are sure the assembler will not destroy its content
# (pseudo instructions often do use it for partial calculations)
skip_ball_draw:
# draw remaining border + next line border and loop for all lines
sw $t2, ($a0) # set 1 yellow at end, and 1 at start of next row
sw $t2, 4($a0)
addi $a0, $a0, 8
addi $t0, $t0, -1
bnez $t0, red_rows_loop
# finish last row to be full yellow
li $a1, 31 # 31 pixels more needed (1 is already there)
move $a2, $t2 # yellow
jal setPixels
# update ball position x
lb $a0, ball_move_x
beq $t3, bounce_pos_x_min, ball_flip_x_dir
bne $t3, bounce_pos_x_max, ball_flip_x_dir_skip
ball_flip_x_dir:
neg $a0, $a0
sb $a0, ball_move_x # store if flipped
ball_flip_x_dir_skip:
add $t3, $t3, $a0 # x += move_x
# update ball position y
lb $a0, ball_move_y
beq $t4, bounce_pos_y_min, ball_flip_y_dir
bne $t4, bounce_pos_y_max, ball_flip_y_dir_skip
ball_flip_y_dir:
neg $a0, $a0
sb $a0, ball_move_y # store if flipped
ball_flip_y_dir_skip:
add $t4, $t4, $a0 # y += move_y
# short delay before next frame, and loop forever
li $v0, 32 # MARS service delay(ms)
li $a0, 40 # 40ms = ~25 FPS if the draw would be instant
syscall
addiu $t1, $t1, 0xFE0408 # adjust background color (red -2, green +4, blue +8 + overflows (B -> G -> R)
andi $t1, $t1, 0xFFFFFF # force "alpha" to zero
j big_loop # infinite loop will animate colours...
# Sets $a1 pixels to $a2 value starting at $a0 (memory fill)
# a0 = pointer to write to, a1 = count of pixels, a2 = value of pixel to set
# a0 will be updated to point right after the last written word
setPixels:
sw $a2, ($a0) # set pixel (or simply memory word)
addi $a0, $a0, 4 # advance memory pointer
addi $a1, $a1, -1 # count-down loop
bnez $a1, setPixels
jr $ra # return
我正在使用 MARS-simulator 的位图显示,单位宽度为 16px,起始地址为 $gp。 我如何使用坐标获取特定像素的地址?
示例 (x,y) 我想我只需要计算像素的数量,直到到达 (x,y) 并将其用作 $gp?
上的偏移量伪:
>ColAmount = 32 #RowLength
>RowAmount = 16 #ColumnHeight
>x = 4
>y = 5
Coordinate = (x, y)
AmountOfPixelsUntilCoordinate = (RowAmount * y) + ColAmount
offset = AmountOfPixelsUntilCoordinate
addressOfPixel = offset($gp)
这是正确的吗?我如何在 MIPS ASM 中实现它?
您还必须提供显示尺寸。即 16x16 "unit" 和 512x256 "display" 表示实际位图分辨率为 32x16 像素(512/16、256/16)。
那么“index of pixel(x, y)”就是y * 32 + x
=> 你有问题。但是要获得内存 offset,你必须适应单个像素的大小,这需要整个 word
,所以 offset = 4 * index
.
最终内存地址为$gp + offset
。
你几乎答对了,只是少了 *4(当然 *4 不用乘法,但只剩下 2:sll $<offset_reg>, $<index_reg>, 2
)。 (*32
是 "shift left by 5")
编辑:通过 (x, y) 位置跟踪某物的示例(即使使用自定义坐标系,在此示例中 "x" 与从左到右的位图 0..31 相同,但 "y"是从0..15从下到上(位图从上到下是0..15)。
计算内存偏移量和绘制像素到Bitmap的主要部分在评论之后:
# when ball is on the current row, draw it *now* (to minimize flickering)
如何运行它:MARS4.5,验证"Delayed branching"是否关闭,工具->位图显示并将其配置为:16x16 单位,512x256 显示(= 位图大小为 32x16 像素), 基地址为 $gp
。编译,运行.
.data
ball_move_x: .byte -1
ball_move_y: .byte 1
.text
.eqv bounce_pos_y_min 1
.eqv bounce_pos_y_max 14
.eqv bounce_pos_x_min 1
.eqv bounce_pos_x_max 30
.eqv adjust_y_pos_xor 15
.eqv ball_colour 0x00d0e0ff
li $t1, 0x00ff0000 #Loading RED in register
li $t2, 0x00ffff00 #Loading YELLOW in register
li $t3, 3 #"ball" x position
li $t4, 3 #"ball" y position (0->15 from bottom upward!)
li $t5, ball_colour
big_loop:
# top row + first column
move $a0, $gp # pointer to write to
li $a1, 33 # 32 pixels for first row, +1 for left column
move $a2, $t2 # yellow
jal setPixels
# 14 red rows with yellow endings+starts
li $t0, 14
red_rows_loop:
li $a1, 30
move $a2, $t1
jal setPixels # set 30 background pixels in middle
# when ball is on the current row, draw it *now* (to minimize flickering)
bne $t4, $t0, skip_ball_draw
xori $at, $t4, adjust_y_pos_xor # y pos goes from BOTTOM! -> flipping it
# y ($t4) pos goes from bottom to make compare with count-down ($t0) simple
# after flipping it, the $at has here real bitmap Y pos going 0->15 from top
sll $at, $at, 5 # calculate offset in $at: at = y_pos * 32
add $at, $at, $t3 # at = y_pos * 32 + x_pos = "index"
sll $at, $at, 2 # at = (y_pos * 32 + x_pos)*4 = "offset"
add $at, $at, $gp # at = gp + offset
sw $t5, ($at) # draw it!
# W: dont't use $at unless you are sure the assembler will not destroy its content
# (pseudo instructions often do use it for partial calculations)
skip_ball_draw:
# draw remaining border + next line border and loop for all lines
sw $t2, ($a0) # set 1 yellow at end, and 1 at start of next row
sw $t2, 4($a0)
addi $a0, $a0, 8
addi $t0, $t0, -1
bnez $t0, red_rows_loop
# finish last row to be full yellow
li $a1, 31 # 31 pixels more needed (1 is already there)
move $a2, $t2 # yellow
jal setPixels
# update ball position x
lb $a0, ball_move_x
beq $t3, bounce_pos_x_min, ball_flip_x_dir
bne $t3, bounce_pos_x_max, ball_flip_x_dir_skip
ball_flip_x_dir:
neg $a0, $a0
sb $a0, ball_move_x # store if flipped
ball_flip_x_dir_skip:
add $t3, $t3, $a0 # x += move_x
# update ball position y
lb $a0, ball_move_y
beq $t4, bounce_pos_y_min, ball_flip_y_dir
bne $t4, bounce_pos_y_max, ball_flip_y_dir_skip
ball_flip_y_dir:
neg $a0, $a0
sb $a0, ball_move_y # store if flipped
ball_flip_y_dir_skip:
add $t4, $t4, $a0 # y += move_y
# short delay before next frame, and loop forever
li $v0, 32 # MARS service delay(ms)
li $a0, 40 # 40ms = ~25 FPS if the draw would be instant
syscall
addiu $t1, $t1, 0xFE0408 # adjust background color (red -2, green +4, blue +8 + overflows (B -> G -> R)
andi $t1, $t1, 0xFFFFFF # force "alpha" to zero
j big_loop # infinite loop will animate colours...
# Sets $a1 pixels to $a2 value starting at $a0 (memory fill)
# a0 = pointer to write to, a1 = count of pixels, a2 = value of pixel to set
# a0 will be updated to point right after the last written word
setPixels:
sw $a2, ($a0) # set pixel (or simply memory word)
addi $a0, $a0, 4 # advance memory pointer
addi $a1, $a1, -1 # count-down loop
bnez $a1, setPixels
jr $ra # return