Banking in IAR and ZX Spectrum 128K by DimkaM ---00--- At the request of TV viewers, as well as for myself as a cheat sheet, I decided to describe working with banking in IAR. I want to disappoint you right away - banking does not apply to variables and constants (with some reservations), only for executable code. This article assumes that you have already read my article in Info Guide #11 and you have an application to IG #11, so as I will refer to the previous examples. First I want to complement the previous article, since many do not read the documentation and ask questions: Q:Why is everything wrapped in modules? R: At a minimum, so that there is no confusion of labels, and when linking (libraries) only used modules are linked. Q:How to pass/receive parameters of C functions in assembler? R: Up to two parameters are passed in registers, the rest via stack If the number of parameters is indefinite (printf(...) etc.), then all parameters are passed through the stack. The first parameter is passed to E, DE, CDE or BCDE, depending depending on the bit depth of the value. If the first and second parameters are not wider than 16 bits each, then the second the parameter is passed in registers B or BC,otherwise via the stack. The return value from the function is passed in registers A (L when banking), HL, CHL or BCHL, depending on the bit depth meanings. ---01--- First we need procedures to call (and return) procedures from switched pages. Or rather, they are already in the libraryz8Oincclz80b.r01, but they designed for a port with an eight-bit address, and even with reading from from the current page. Therefore, we will replace (so as not to constantly link) in this library the procedures we need. Let's create a project directoryfix_clz80b. Create a file in this directoryzx128k.s01 with the following content: ;since there is no hardware way to find out the current page in ;window OxcOO0-Oxffff, ;then each page (participating in banking) will store its ;number at OxFFFF. MODULE MY_CURRENT_PAGE PUBLIC MY_CURRENT_PAGE MY_CURRENT_PAGE=Oxffff ENDMOD MODULE ?BANK_CALL_DIRECT_L08 PUBLIC ?BANK_CALL_DIRECT_L08 EXTERN MY_CURRENT_PAGE RSEG RCODE ?BANK_CALL_DIRECT_L08: push hl ld hl,(MY_CURRENT_PAGE-1) push bc ld bc,0x7ffd out (c),a pop bc ex (sp),hl jp (hl) ENDMOD MODULE ?BANK_LEAVE_32_L08 PUBLIC ?BANK_LEAVE_32_L08 EXTERN MY_CURRENT_PAGE RSEG RCODE ?BANK_LEAVE_32_L08: ld sp,ix pop ix pop de inc sp inc sp pop af push bc ld bc,0x7ffd out (c),a pop bc ret ENDMOD MODULE ?BANK_LEAVE_DIRECT_L08 PUBLIC ?BANK_LEAVE_DIRECT_L08 PUBLIC ?BANK_FAST_LEAVE_L08 EXTERN MY_CURRENT_PAGE RSEG RCODE ?BANK_LEAVE_DIRECT_L08: ld sp,ix pop ix pop de pop bc ?BANK_FAST_LEAVE_L08: pop af push bc ld bc,0x7ffd out (c),a pop bc ret ENDMOD MODULE ?BANK_CALL_DIRECT_EXAF_L08 PUBLIC ?BANK_CALL_DIRECT_EXAF_L08 EXTERN MY_CURRENT_PAGE RSEG RCODE ?BANK_CALL_DIRECT_EXAF_L08: ex af,af' ld a,(MY_CURRENT_PAGE) push af ex af,af' push bc ld bc,0x7ffd out (c),a pop bc jp (hl) END Далее нам понадобится файлzx128k.bat с содержимым: ..z8Obinaz80 -uu -b -v0 zx128k.s01 copy ..z8Olibclz80b.r01 ..z8Olibclzx128k.r01 /Y ..z8Obinxlib -c "fetch-modules zx128k.r01 ..z8Olibclzx128k.r01 MY_CURRENT_PAGE MY_CURRENT_PAGE" ..z8Obinxlib -c "replace-modules zx128k.r01 ..z8Olibclzx128k.r01" Запускаем его, и у нас появляется библиотека ..z8Oincclzx128k.r01 - это копия библиотекиclz80b.r01 с заменёнными процедурами банкинга. ПроектWe won't need fix_clz80b anymore. ---02--- Now we will rework the printing procedures from the previous one for banking articles. Let's create a directorymylibb, with a subdirectory list in it. Copy the filesmylib.c to the current project (renaming them to putchar.c ) andgraf.s01 from the mylib directory (see article in Info Guide #11 ). graf.s01 will be edited as follows: We will put the FastPixel and the table in non-banked memory, i.e. in RCODE segment. Accordingly, the way out of it is the usual ret. MODULE fast_set_pix PUBLIC fast_set_pix,fast_set_pix_table RSEG RCODE ;NON-BANKED segment fast_set_pix ;http://zxdn.narod.ru/coding/zg1etud2.txt ... procedure body ... ret ;normal output RSEG ALIGN8 fast_set_pix_tableDEFS 1024 ENDMOD We will define the initialization of tables and the slow pixel in a bankable CODE segment, in this case it is necessary to use the library exit procedure. MODULE fast_set_pix_init PUBLIC fast_set_pix_init EXTERN fast_set_pix_table,?BANK_FAST_LEAVE_L08 RSEG CODE ;banked segment fast_set_pix_init ... procedure body ... ;ret will be replaced with exit from the page: JP LWRD ?BANK_FAST_LEAVE_L08 ENDMOD MODULE little_set_pix PUBLIC little_set_pix EXTERN ?BANK_FAST_LEAVE_L08 RSEG CODE ;banked segment little_set_pix ... procedure body ... ;ret will be replaced with exit from the page: JP LWRD ?BANK_FAST_LEAVE_L08 END Let's createbuild.bat: ..z8Obiniccz80 -v0 -mb -uua -b -q -x -K -gA -z9 -t4 -T -Olist -Llist -Alist -I"../z80/inc/" putchar.c ..z8Obinaz80 -uu -b -v0 -Olist graf.s01 The -mb option indicates the need to compile all functions under banking calls, because library puts and printf expect putchar bankable function. Let's add the library layout there: del /Q mylibb.r01 ..z8Obinxlib -c "fetch-mod listputchar.r01 mylibb.r01" "fetch-mod listgraf.r01 mylibb.r01" "LIST-ALL-SYMBOLS mylibb.r01 listmods.txt" We collect the library with this batch file. In the new file'mylibb.h' we will describe the variable MY_CURRENT_PAGE, ituseful if you need to find out the current page: extern unsigned char MY_CURRENT_PAGE; And other functions, not forgetting to specify banking modifiers: banked void scr_init(char atribute); #ifdef FASTPIXEL banked void fast_set_pix_init(void); non_banked void fast_set_pix(unsigned char x,unsigned char y); #define set_pix fast_set_pix #define set_pix_init fast_set_pix_init #else #define set_pix_init() banked void little_set_pix(unsigned char x,unsigned char y); #define set_pix little_set_pix #endif The banked modifier need not be specified, because by default we have everything is banked, but it’s better to indicate - it may come in handy later. ---03--- So, finally, the preparations for HelloWorld are over.Let's check that we did it. Let's create a project'HelloWorld', in it there will be subdirectories list and bin FileLnk.xcl: -cZ80 //processor //-P(CODE)CODE=[C000-FFFF]*2+10000, //[3C000-ЗFFFF]*2+10000,[6C000-бFFFF]*2+10000 //select banks //0,1,3,4,6,7 for banking (we don’t use 5 and 2, because they are nailed down) //but we will also take into account the bit (in port 7ffd) for selecting 48K ROM. If necessary //ROM 128K, then use the previous line: -P(CODE)CODE=[10C000-1OFFFE]*2+10000, [13C000-1ЗFFFE]*2+10000,[16C000-1бFFFE]*2+10000 -Z(CODE)RCODE,CDATAO,CONST,CSTR,CCSTR=6000-7FFF //segments //memories with constants and code -Z(DATA)DATAO,IDATAO,UDATAO,ECSTR,ALIGN8|8,CSTACK+200=8000-BFFF //segments of the stack, variables, etc. -e_medium_write=_formatted_write //printf/sprintf configuration -e_medium_read=_formatted_read //scanf/sscanf configuration ../mylibb/mylibb //link your library -C ../z80/lib/clzx128k //connect the IAR library -FMOTOROLA -o list/aout.a01 -l list/cout.html -xehinms //include everything for completeness -R -w47 //suppress warnings that I haven't understood yet //how to get rid of Build.bat file: ..z8Obiniccz80 -v0 -mb -uua -q -e -K -gA -s9 -t4 -T -Llist -Olist -Alist -I"../z80/inc/" main.c ..z8Obinaz80 -Olist -Dbanking Cstartup.s01 ..z8Obinxlink -Ilist main cstartup -f Lnk.xcl Let's copycstartup from the previous article and add numbering pages by adding the following code immediately after theinit_C label: #ifdef banking #if NOTprocбЧ180 EXTERN MY_CURRENT_PAGE ld hl,MY_CURRENT_PAGE ld bc,0x7ffd ld a,0x17 bankIniLoop: REPT 2 out (c),a ld (hl),a dec a ENDR dec a cp OxOe jr nz,bankIniLoop #endif #endif Создадимmain.c: #include #include #include //#define FASTPIXEL #include "../mylibb/mylibb.h" void KbdScan(void){ printf("Keyboard scan: 0x%02Xr",input(OxOOfe)); } C_task void main(void){ unsigned char x=0; scr_init(0x07<<3); set_pix_init(); puts("Hello World!"); do{ set_pix(x,(sin((double)x/20)*20+95)); }while(++x); while(1) KbdScan(); } Компилируем батником. ---04--- Опять засада: что делать с файломlistaout.a01 !? Этотfile inmotorola s-records format. To convert the fileaout.a01 we will use a third-party SRecord utility - you can find it in the appendix to this newspaper. Add tobuild.bat (attention! designed for the starting address 0x6000 !): @echo off ..z8Osrecordsrec_cat listaout.a01 -offset -0x6000 -crop 0 0x6000 -o bincode.c -Binary FOR %%i IN (00,01,03,04,06,07,10,11,13,14,16,17) do ..z8Osrecordsrec_cat listaout.a01 -offset -0x%%~iCOO0 -crop 0 0x4000 -o bin%%~i.c -Binary for /R bin %%i in (*.c) do (if %%~zi==0 (del /Q %%i) ELSE (echo crop file:%%~nxi size:%%~zi out^(7FFD^),0x%%~ni)) echo on A binary code file will be created in thebin directory, which you need to download and run from address 0x6000, as well as the files with the number (taking into account the ROM selection bit) of the page in the name - theirs, Naturally, you need to download it page by page. You may have your own methods for creating the bootloader and image disk. If not, you can add the following line to build.bat: ..z8Obinbuild128k.bat buildscl And you will receive an scl file with all the files and the loader as output. Let's launch and enjoy the pure sine. * * * In the next episode we'll look at dirty hacks. For example, how put local variables and constants in the banked segment.
Share your thoughts about the article