Here's another program, though really it's more of a drawing routine for programs to use, with a demonstration drawing.
(I didn't care to do the win screen again, and this better shows off some of what it can do, such as the dotted/multicolored lines, and the wrapping trick.)
It doesn't itself use overlays, but is small enough to fit within a single overlay, and could easily be adjusted to take the drawing as a parameter instead of hardcoding it. (This would actually make the program smaller.)
As such, it should work with any basic bootloader - though I discovered that the built-in bootloader starts running the program at address 4 instead of 0, which doesn't work for this program. (I could make it work, but haven't bothered to.)
In some ways, this is a line drawing routine, as it can easily draw several common types of lines (though not all of them) - but really, it'd be more accurate to call it a repeated-pixel placer.
The routine is given the address of a drawing on disk, which consists of a list of words that each describes a "line" to draw. It draws each in turn, until it hits a list terminator.
Each word of that list consists of the start pixel (where to start drawing), the stop pixel (where to stop drawing), and an increment (how much to change the position by for each step). The list terminator is a word where the start pixel is equal to the stop pixel. (It is worth noting that the stop pixel is never drawn, while the start pixel is - and that the stop pixel must be exact, that is, a position that would be drawn to if it wasn't the stop pixel.)
It's fairly fast - 3 cycles per pixel drawn (2 if IFJMP is instant), plus some setup for each word and for the routine as a whole. (I calculated that it spends 496 cycles to draw just the background and window frame, which in the demo is just the first 5 words of the drawing.)
Note that the code given below, while ready to be pasted into Senbir, is actually the output I got from my preprocessor when given the original source code - that source may be easier to read.
// Draws lines by repeatedly adding an increment to a pixel. // Overlay main started at address 0 DATAC 00000000000000000000000000010000 // End address for overlay // Assumed: R15 = 1 MOVI 5 15 // R5 = ram[..] : load address of data to be drawn MATH 4 4 1 // R4 = 0 : initialization for updating only parts of it MATH 3 3 1 // R3 = 0 : initialization for updating only parts of it MATH 2 2 1 // R2 = 0 : initialization for updating only parts of it // Label next found at address 5 GETDATA 1 3 5 // R1 = read(disk, R5) : load next step MATH 15 5 0 // R5++ : update address PMOV 1 2 0 8 0 0 // R2[0:8] = R1[ 0: 8] : set start pixel PMOV 1 3 9 17 9 0 // R3[0:8] = R1[ 9:17] : set end pixel IFJMP 1 14 0 // jump to done if R2 == R3 PMOV 1 4 18 26 18 0 // R4[0:8] = R1[18:26] : set position increment // Label loop found at address 11 SETDATA 0 3 2 // Draw a pixel from R2 MATH 4 2 0 // R2 += R4 : increment position IFJMP 1 10 1 // jump to loop if R2 != R3 JMP 1 4 // jump to next otherwise // // Label done found at address 15 HLT // // Label data_addr found at address 16 DATAC 00000000000000000000000000010001 // // Overlay main ended at address 16 // // Label demo_data found at address 17 // Start pixel (is drawn), stop pixel (is not drawn), position increment DATAC 10000100110111011100000000100000 // Main area fill, TL-to-BR DATAC 01111011100111111111111100000000 // Bottom row, R-to-L DATAC 01000011000111111111111111100000 // Left column, B-to-T DATAC 01000100010000000000000100000000 // Top row, L-to-R DATAC 01111100110000000000000000100000 // Right column, T-to-B // DATAC 00000101000010111000000100100000 // Black \ line DATAC 11000110111010100100000011100000 // Light-green / line // DATAC 00010100100111100100001000000000 // Dotted line 1: 2px DATAC 00010101001000101000001100000000 // Dotted line 2: 3px DATAC 00010101101000101100010000000000 // Dotted line 3: 4px // DATAC 00010110100111110100001000000000 // 2-color line part 1 DATAC 01011010110000010100001000000000 // 2-color line part 2 // DATAC 00010111001000111000001100000000 // 3-color line part 1 DATAC 11011011011111111000001100000000 // 3-color line part 2 DATAC 01011111010000011000001100000000 // 3-color line part 3 // DATAC 00000000000000000000000000000000 // End of list
(Feel free to use this code for your own purposes, same as with any other Senbir assembly code I post in this forum - I wouldn't have posted it if I minded.)