Here's a dirty little trick that I've grown accustomed to when making ROM images to burn:
Code:
.model tiny,c
ROM_PAGES equ 4
ROM_BYTES equ ROM_PAGES*512
video_seg segment at 0b800h
video_seg ends
.code
code_start:
dw 0AA55h
db ROM_PAGES
main proc
mov ax, seg video_seg
mov ds, ax
mov si, 00h
mov cx, 1000h
mov ax, 0AA55h
loop_vid:
mov word ptr ds:[si], ax
inc si
inc si
loop loop_vid
int 3
main endp
db (ROM_BYTES - ($-code_start) -32) dup (0) ; filler
; The following is entered with a G= in DEBUG. It computes and stores
; the checksum. It's always located 20h bytes before the end of the ROM.
Checkit proc
mov si,100h ; where files get loaded in DEBUG
mov di,ROM_BYTES-1
xor ax,ax
Check2:
add al,cs:[si]
inc si
dec di
jnz Check2
neg al
mov cs:[si],al ; stores result in "Checksum"
int 3
Checkit endp
db (ROM_BYTES - ($-code_start) -1) dup (0)
Checksum db 0
end
(Note that I've changed the segment to B800 and the length to 4K to give you a nice green screen. At any rate, run DEBUG on the .COM file and G=8E0 into the checksum routine. It'll compute and store the checksum and exit to DEBUG. Then issue a -W command to DEBUG and then a -Q. Presto--you have your checksummed image.
Why is the checksum loaded 32 (decimal) bytes before the end of the ROM?
Also, you asked why I used multiple segments in a COM file and not declare a memory model?
Well, 4 reasons to be honest:
1. I keep a small MASM-compatible assembler on my IBM PC for on-the-fly debugging, and it doesn't appear to support the memory models (Arrowsoft Assembler). Perhaps it even predates them? I know the BIOS is considered COMPACT, but I can't find the memory model declaration in IBM's listings.
2. I once heard that COM files, such as COMMAND.COM need not actually be limited to 64kB and I wanted to figure out how that might be done- turns out, the assembler/linker doesn't care if the memory model is tiny/multiple segments are used and compiling as COM or EXE only changes the properties of the header (or lack thereof).
3. Though I don't care too much if the assembler changes some instructions, I'm big on describing my intent in x86 instructions, and memory models let me hide my intent, i.e. make assumptions, with regard to where I'm trying to access code and data. Quite appropriately, it is the same reason I barely use ASSUME at all.
4. I have
never found a satisfactory explanation on what assumptions are made by the programmer/assembler using simplified segment directives, and how the assembler changes how it generates code in response to seeing the simplified segments. Ditto with how the linker links 'full' segments vs 'simplified segments.
x86 is complicated enough... the less assumptions I forced a reader
or myself to make, the less painful it is.