/* This is a simple demonstration file for the Zeus assembler. If you want more sustantial files they're available at www.desdes.com Segments Segments are a way to organise where in memory things are put. For example, when writing a routine you may well want to have both code and data. Ideally these two things should be placed near to each other in the source so you can see them together, but in practice they may well need to be placed far apart in memory. Code might, for example, need to be placed in one area of memory (FLASH) while data would be placed in another (RAM)... Traditionally variables would be placed at the start or end of memory and the code in the middle, meaning that they were separated by many, many lines of source, or alternately the variables would be interspersed in with the code and so interspersed in real memory. This makes for both ugly and potentially dangerous code... Segments let you manipulate the assembly position so that adjacent statements can refer to different sections of memory. An example might make this clearer: ; Now, let's tell Zeus which segments exist and where they belong segment code = $6000,$2000 ; Starts at $6000, no more than $2000 bytes long segment data = $8000,$1000 ; Starts at $8000, no more than $1000 bytes long segment code ; Select the code segment Print proc ; Print scope starts push ix,hl,de,bc,af ; Save them cp cWhite+1 ; jr c,PrintColour ; ; Etc, etc ld a,(pCurX) ; add a,(hl) ; ld (pCurX),a ; PrintExit pop af,bc,de,hl,ix ; ret ; segment data ; Select the data segment ; Print variables pCurX db 0 ; A logical X position ppCurY db 0 ; A logical Y position pCurY dw 0 ; The actual address CurCol db 0 ; The cursor colour segment code ; Back to the code segment PrintStr proc ; Blah blah... Now, what Zeus will do is put the PrintStr code immediately after the Print code, starting at $6000, and the variables will be put starting at $8000. There's nothing sacred about the names "code" and "data", by the way. You could call them "george" and "mildred" for all zeus cares. (From v1.7 onward Zeus will no longer let you use the same name for a segment and a normal label) If you don't mention segments at all zeus will behave like a normal z80 assembler and just dump bytes into memory where you tell it too. If you do mention segments then it is a requirement that you must tell zeus where the segments start and end before you use them. I have wondered about allowing zeus to decide on the segment sizes and order in memory automatically, but there seem to be quite a few little niggles with this, so for the sort of applications we're talking about for this zeus I've decided to leave this up to the programmer... Zeus will, of course, issue error messages if you try to plant code outside of the range of the current segment. ORG statements inside a segment are perfectly valid. So are DISP statements but (of course) these only affect data in that segment. Segments can overlap. It is undefined what bytes will be placed in memory when this happens; it will normally be the ones placed by the statements nearer the end of the combined sources, but this behaviour is subject to change. Segment use with macros Consider a macro that is being used in one segment, when the macro body is written in another. Which segment do you think the code generated by the macro will use? The first. Macros always 'execute' in the context of the caller. However, should a macro include a segment statement, then that segment statement will determine the segment used for the rest of the bytes generated by the macro. When the macro finished zeus will restore the segment back to the segment being used before the macro call. When macros are called recursively or from inside other macros the segment can be changed during each nesting and will be restored on each return. */ ; Example code to demonstrate segments. ; This code is garbage, it doesn't mean anything segment code = $6000,$100 ; Starts at $6000, no more than $100 bytes long segment data = $6200,$100 ; Starts at $6200, no more than $100 bytes long segment code ; Select the code segment Print proc ; Print scope starts ld hl,Start ; A forward reference to a local label Start push ix,hl,de,bc,af ; Save them ; Etc, etc ld a,(pCurX) ; add a,(hl) ; ld (pCurX),a ; PrintExit pop af,bc,de,hl,ix ; retp ; segment data ; Select the data segment ; Print variables pCurX db 1 ; A logical X position ppCurY db 1 ; A logical Y position pCurY dw 1 ; The actual address CurCol db 1 ; The cursor colour segment code ; Back to the code segment db 42 halt halt halt halt ; Blah blah... ; Tell zeus not to export the symbol table, but to show us any ; segments export_sym "",%1 1 0 00 00 ; Blank filename means no export /* Now, have a look at the Zeus symbols. The settings in the line above will have caused (should have caused) the segments to have been added to the symbol table. The segments are displayed as follows: code EQU $6000; Length = $0100, Final PC = $601C, Est. size = $001C data EQU $6200; Length = $0100, Final PC = $6205, Est. size = $0005 Note that the BASE of the segment is the symbol and the LENGTH and Final PC values are shown as comments. The PC value does not necessarily indicate the maximum size of the segment, because the PC could have been manipulated using an ORG statement, but if you have not done anything nasty (backwards ORGs) then you could use the "Est. size" information to adjust the segment length and base values to arrange them efficiently in memory. Remember that Zeus will grump at you if you make the segments too small so a mistake here shouldn't be silently dangerous... */