Thanks for the comments.
Timothy Normand Miller wrote:
Readdressing the little-endian thing, were you saying that the way
glyph bits are stored in the VGA font is big-endian? If so, then that
was my mistake.
Yes, from my reading of several different books on the VGA, the fonts
are stored with the MSB of each octet as the left most pixel. I change
my mind every day about whether this is the right way around or not, but
that is only a philosophical issue now.
Read on...
>> ; HERE!
>> > let G_VID_SCREEN_WIDTH = 0x100
>> > let G_VID_GLYPH_HEIGHT_M1 = 0x101
>
> Are these addresses in scratch memory?
Yes, it was my intention that these would be in scratch memory. I'm not
sure how we're going to allocate things there yet. They could also be
passed in registers, but I can see no advantage in that.
move ((123000000)/65536)+1, r6
shiftu r6, 16, r6
add r6, -11072, r6 ; ((123000000)%65536)
We're going to have to get help from Petter about how to do this
properly. Also, what is the meaning of the 123000000 that you're
trying to store in r6?
Petter's a new feature to make this easier, thanks Petter. I'm loading
a large number with zeros on the left into the pixel address so that in
the simulator I can see easily that I am incrementing the pixel address
by the amount I thought I should be. This 'frame' is only for testing.
move 0x12, r7
move 0x34, r8
noop
jump draw_glyph, r9
noop
noop
jump 510
What code is going to be fixed at 510?
In the simulator, jumping to address 510 stops the simulation.
noop
endframe
;;; ------------------------------------------------------------------------
;;; draw_glyph(r6: pixel_addr, r7: fg_color, r8: bg_color, r9: continuation)
frame draw_glyph
alias p0..p3 = r6..r9
alias q0..q3 = r0..r3
protect r4..r5
protect r10..r31
; p0 = pixel address
; p1 = fg color
; p2 = bg color
; p3 = return address
;
; q0 = general scratch register
; q1 = y counter
; q2 = mask (and x counter) / second scratch
; q3 = font data
;
; Global data:
;
; G_VID_SCREEN_WIDTH
; The offset to add to the pixel_address to move down one line
; G_VID_GLYPH_HEIGHT_M1
; The height of a font character (minus 1)
;
; It is assumed that the glyph data is contained in consecutive
; 8-bit chunks of the data being read from memory. The least
; signifigant 8-bits are the first (top) line. For each line,
; the most significant bit is assumed to be the left-most bit.
; This matches the VGA (and common sense?).
Good comments! :)
If the bytes are little-endian relative to each other, then it makes
sense for the bits in the bytes to also be little-endian. That's
common sense to me. But it would not surprise me at all if they
didn't do it that way. On x86, X11 stores bitmaps internally in a
truly little-endian manner, whereas GDI in Windows stores the bytes
little-endian but the bits big-endian. To a large degree, it's all
purely arbitrary, although some combinations are easier to remember
and therefore less bug-prone.
draw_glyph:
; We use Q1 as our height counter, starting from 0
move 0, q1
glyph_loop:
; Every fourth scan line we need to read a new uint32 of
; glyph data. The code is smaller if I only have one loop,
; as opposed to the two in Tims original C version.
and q1, 3, q0
jnzero q0, glyph_no_get
; Shift the glyph data.
shiftu q3, -8, q3
move [MEM_READQ_DATA], q3
glyph_no_get:
What you did is just fine. We'll revisit this when we run this in the
real hardware. If the framerate is less than 10fps, we'll look into
making optimizations that add more code to make it faster. Unrolled
loops and such. I can't really judge the difference here, and since
you're the one doing the hard work to hand-code the assembly, I'm not
going to argue with you. :)
; We now check to see if thre are at least 9 free spaces
; in the command Q. If there are fewer than 9 we loop.
One for the address, 8 for the data.
;
; R2 is the mask that we will use below, we might as well
; load that up now in the delay slot after the memory read.
q2?
One of the biggest crimes in software is when the comments get out of
step with the code. I'm sorry, I'll try to not let it happen again. ;-).
glyph_loop_cmd:
move [MEM_CMDQ_FREE], q0
move 0x80, q2
sub q0, 9, q0
jneg q0, glyph_loop_cmd
noop
; Set the current pixel address.
move p0, [MEM_SEND_ADDR_MEM]
; We now loop over the eight horizontal pixels of the
; glyph data. To count this loop we are using the mask
; that has been initialised to 0x80. Once we have shifted
; it right until it is zero we are done.
glyph_loop_x:
; And the mask with the glyph data, and load R0 with either
; the foreground color or the background color.
and q3, q2, q0
jzero q0, glyph_bg
move p2, q0
move p1, q0
glyph_bg:
; Shift the mask and loop if non-zero. The store to video
; mem is done in the delay slot.
shiftu q2, -1, q2
jnzero q2, glyph_loop_x
move q0, [MEM_SEND_DATA_1111]
; Read the screen width and the glyph height
move [G_VID_SCREEN_WIDTH], q0
move [G_VID_GLYPH_HEIGHT_M1], q2
; Move pixel addr to the next line down
add p0, q0, p0
; If our height counter is equal to the glyph height then
; we are done
sub q1, q2, q0
jnzero q0, glyph_loop
add q1, 1, q1
jump p3
noop
endframe
Very sweet!
Thanks, I really enjoy this sort of coding, and there's very little
need for it any more. At work, I'm quite against anyone ever checking
in any assembler, it can be very hard for the non-author to debug.
_______________________________________________
Open-graphics mailing list
[email protected]
http://lists.duskglow.com/mailman/listinfo/open-graphics
List service provided by Duskglow Consulting, LLC (www.duskglow.com)