获取位图显示 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