diff --git a/docs/library.md b/docs/library.md index b7af7b70f..ca1e6d93e 100644 --- a/docs/library.md +++ b/docs/library.md @@ -126,7 +126,12 @@ Will print 64 characters to a line (grid, not proportional), and 32 lines of tex Upping the standard 768 character screen to 2048 characters of text on one screen at once. Works in a similar way to print42. This version uses screen tables. -####Compression / Decompression Library +#### Memory Banking + +* [memorybank.bas](library/memorybank.md) +
Library to access RAM banks and get advantage of extra RAM in 128k models. + +#### Compression / Decompression Library * [megaLZDepack.bas](library/megalz.bas.md)
Routine wrapping the megaLZ decompression algorithm. diff --git a/docs/library/memorybank.md b/docs/library/memorybank.md new file mode 100644 index 000000000..bc491851c --- /dev/null +++ b/docs/library/memorybank.md @@ -0,0 +1,28 @@ +# MemoryBank + +The MemoryBank library allows you to manage paged memory on 128K and later/compatible models. + +This library includes three commands: +- [SetBank](memorybank/setbank.md): Sets the specified bank to memory location $c000. +- [GetBank](memorybank/getbank.md): Returns the memory bank that is located at memory location $c000. +- [SetCodeBank](memorybank/setcodebank.md): Copies the specified memory bank to location $8000 + +Only works on 128K and later/compatible models. + +**Danger:** If our program exceeds the address $c000 it may cause problems, use this library at your own risk. + + +## Menory banks +- $c000 > Bank 0 to Bank 7 +- $8000 > Bank 2 (fixed) +- $4000 > Bank 5 (screen) +- $0000 > ROM + +Banks 2 and 5 are permanently fixed at addresses $8000 and $4000, so it is not common to use them. + +Banks 1, 3, 5 and 7 are banks in contention with the ULA, their use is not recommended in processes requiring maximum speed. + +## See also +- [SetBank](memorybank/setbank.md) +- [GetBank](memorybank/getbank.md) +- [SetCodeBank](memorybank/setcodebank.md) diff --git a/docs/library/memorybank/getbank.md b/docs/library/memorybank/getbank.md new file mode 100644 index 000000000..c04692d05 --- /dev/null +++ b/docs/library/memorybank/getbank.md @@ -0,0 +1,53 @@ +# GetBank + +## Syntax + +``` +#include + +PRINT "Current bank at $c000: ";GetBank() +``` + +## Description +Returns the memory bank located at $c000 based on the system variable BANKM. + +Only works on 128K and compatible models. + +**Danger:** If our program exceeds the address $c000 it may cause problems, use this function at your own risk. + + +## Memory banks +- $c000 > Bank 0 to Bank 7 +- $8000 > Bank 2 (fixed) +- $4000 > Bank 5 (screen) +- $0000 > ROM + +Banks 2 and 5 are permanently fixed at addresses $8000 and $4000, so it is not common to use them. +Banks 1, 3, 5 and 7 are banks in contention with the ULA, their use is not recommended in processes requiring maximum speed. + + +## Examples + +```basic +#include "memorybank.bas" + +DIM n AS UByte + +' Fill banks with data +FOR n = 0 TO 7 + SetBank(n) + PRINT AT n,0;"Bank: ";n; + POKE $c000,n + PRINT " > ";GetBank(); +NEXT n + +' Read banks +FOR n = 0 TO 7 + SetBank(n) + PRINT AT n,15;PEEK($c000); +NEXT n +``` + +## See also +- [SetBank](setbank.md) +- [SetCodeBank](setcodebank.md) diff --git a/docs/library/memorybank/setbank.md b/docs/library/memorybank/setbank.md new file mode 100644 index 000000000..52a88e9db --- /dev/null +++ b/docs/library/memorybank/setbank.md @@ -0,0 +1,52 @@ +# SetBank + +## Syntax + +``` +#include + +SetBank(3) +``` + +## Description +Place the bank indicated by bankNumber in the memory slot between $c000 and $ffff and updates the system variable BANKM. + +Only works on 128K and compatible models. + +**Danger:** If our program exceeds the address $c000 it may cause problems, use this function at your own risk. + + +## Memory banks +- $c000 > Bank 0 to Bank 7 +- $8000 > Bank 2 (fixed) +- $4000 > Bank 5 (screen) +- $0000 > ROM + +Banks 2 and 5 are permanently fixed at addresses $8000 and $4000, so it is not common to use them. +Banks 1, 3, 5 and 7 are banks in contention with the ULA, their use is not recommended in processes requiring maximum speed. + + +## Examples + +```basic +#include + +DIM n AS UByte + +' Fill banks with data +FOR n = 0 TO 7 + SetBank(n) + PRINT AT n,0;"Bank: ";n; + POKE $c000,n +NEXT n + +' Read banks +FOR n = 0 TO 7 + SetBank(n) + PRINT AT n,10;PEEK($c000); +NEXT n +``` + +## See also +- [GetBank](getbank.md) +- [SetCodeBank](setcodebank.md) diff --git a/docs/library/memorybank/setcodebank.md b/docs/library/memorybank/setcodebank.md new file mode 100644 index 000000000..27e9cf28b --- /dev/null +++ b/docs/library/memorybank/setcodebank.md @@ -0,0 +1,65 @@ +# SetCodeBank + +## Syntax + +``` +#include + +SetCodeBank(3) +``` + +## Description +Place the bank indicated by bankNumber in the memory slot between $c000 and $ffff and updates the system variable BANKM. +This command is applicable to the architecture described in chapter 14 of the Boriel Basic for ZX Spectrum book. + +Only works on 128K and compatible models. + +**Danger:** If our program exceeds the address $c000 it may cause problems, use this function at your own risk. +Bank 2 is destroyed in this operation, apart from the contents of $8000 to $bfff, so it should not be used. + + +## Memory banks +- $c000 > Bank 0 to Bank 7 +- $8000 > Bank 2 (fixed) +- $4000 > Bank 5 (screen) +- $0000 > ROM + +Banks 2 and 5 are permanently fixed at addresses $8000 and $4000, so it is not common to use them. +Banks 1, 3, 5 and 7 are banks in contention with the ULA, their use is not recommended in processes requiring maximum speed. + + +## Examples + +``` +#include + +DIM n, b AS UByte + +' Fill banks with data +FOR n = 0 TO 7 + SetBank(n) + PRINT AT n,0;"Bank: ";n; + POKE $c000,n +NEXT n + +' SetCodeBank +FOR n = 0 TO 7 + PRINT AT n+1,16;">";n; + SetCodeBank(n) + IF n = 2 THEN + PRINT ">SKIP"; + ELSE + b = PEEK($8000) + PRINT ">";b; + IF b = n THEN + PRINT ">OK"; + ELSE + PRINT ">ERROR"; + END IF + END IF +NEXT n +``` + +## See also +- [SetBank](setbank.md) +- [GetBank](getbank.md) diff --git a/examples/memory_banking.bas b/examples/memory_banking.bas new file mode 100644 index 000000000..b254dbb28 --- /dev/null +++ b/examples/memory_banking.bas @@ -0,0 +1,81 @@ +' --------------------------------------------------------- +' - MemoryBank.bas library Test --------------------------- +' --------------------------------------------------------- +' Compile at 24576 + + +#include "memorybank.bas" + + +Main() +DO:LOOP + + +SUB Main() + CLS + Test_SetBank() + PAUSE 0 + CLS + SetBankSample() +END SUB + + +SUB Test_SetBank() + DIM n, b AS UByte + + ' SetBank and GetBank + FOR n = 0 TO 7 + PRINT AT n+1,0;"Bank: ";n; + SetBank(n) + PRINT ">";GetBank(); + POKE $c000,n + NEXT n + + ' Test banks + FOR n = 0 TO 7 + PRINT AT n+1,9;">";n; + SetBank(n) + b = PEEK($c000) + IF b = n THEN + PRINT ">OK"; + ELSE + PRINT ">ERROR"; + END IF + NEXT n + + ' SetCodeBank + FOR n = 0 TO 7 + PRINT AT n+1,16;">";n; + SetCodeBank(n) + IF n = 2 THEN + PRINT ">SKIP"; + ELSE + b = PEEK($8000) + PRINT ">";b; + IF b = n THEN + PRINT ">OK"; + ELSE + PRINT ">ERROR"; + END IF + END IF + NEXT n +END SUB + + +SUB SetBankSample() + DIM n, b AS UByte + + ' Fill banks with data + FOR n = 0 TO 7 + SetBank(n) + PRINT AT n,0;"Bank: ";n; + POKE $c000,n + NEXT n + + ' Read banks + FOR n = 0 TO 7 + SetBank(n) + PRINT AT n,10;PEEK($c000); + NEXT n + +END SUB diff --git a/src/lib/arch/zx48k/stdlib/memorybank.bas b/src/lib/arch/zx48k/stdlib/memorybank.bas new file mode 100644 index 000000000..38435060d --- /dev/null +++ b/src/lib/arch/zx48k/stdlib/memorybank.bas @@ -0,0 +1,82 @@ +' ---------------------------------------------------------------- +' This file is released under the MIT License +' +' Copyleft (k) 2023 +' by Juan Segura (a.k.a. Duefectu) +' +' Memory bank switch tools +' ---------------------------------------------------------------- + +#ifndef __LIBRARY_MEMORYBANK__ + +REM Avoid recursive / multiple inclusion + +#define __LIBRARY_MEMORYBANK__ + + +' ---------------------------------------------------------------- +' Place the bank indicated by bankNumber in the memory slot +' between $c000 and $ffff and updates the system variable BANKM. +' Only works on 128K and compatible models. +' Danger: If our program exceeds the address $c000 it may cause +' problems, use this function at your own risk. +' Parameters: +' bankNumber (UByte): Bank number to place at $c000 +' ---------------------------------------------------------------- +SUB FASTCALL SetBank(bankNumber AS UByte) +ASM + ; A = bankNumber to place at $c000 + ld d,a ; D = bankNumber + ld a,($5b5c) ; Read BANKM system variable + and %11111000 ; Reset bank bits + or d ; Set bank bits to bankNumber + ld bc,$7ffd ; Memory Bank control port + di ; Disable interrupts + ld ($5b5c),a ; Update BANKM system variable + out (c),a ; Set the bank + ei ; Enable interrupts +END ASM +END SUB + + +' ---------------------------------------------------------------- +' Returns the memory bank located at $c000 based on the system +' variable BANKM. +' Only works on 128K and compatible models. +' Returns: +' UByte: Bank number placed at $c000 +' ---------------------------------------------------------------- +FUNCTION FASTCALL GetBank() AS UByte + RETURN PEEK $5b5c bAND %111 +END FUNCTION + + +' ---------------------------------------------------------------- +' Place the bank indicated by bankNumber in the memory slot +' between $c000 and $ffff, copy the contents to $8000-$bfff and +' restore the bank that was at $c000 before you started. +' Only works on 128K and compatible models. +' Danger: The contents of memory located between $8000 and $bfff +' are lost, and if our program exceeds the address $8000 it may +' cause problems, use this function at your own risk. +' Parameters: +' bankNumber (UByte): Bank number to place at $8000 +' ---------------------------------------------------------------- +SUB SetCodeBank(bankNumber AS UByte) + DIM b AS UByte + + b = GetBank() + SetBank(bankNumber) + +ASM + ; Copy from $c000-$ffff to $8000-$bfff + ld hl,$c000 + ld de,$8000 + ld bc,$4000 + ldir +END ASM + + SetBank(b) +END SUB + +#endif diff --git a/src/lib/arch/zxnext/stdlib/memorybank.bas b/src/lib/arch/zxnext/stdlib/memorybank.bas new file mode 100644 index 000000000..38435060d --- /dev/null +++ b/src/lib/arch/zxnext/stdlib/memorybank.bas @@ -0,0 +1,82 @@ +' ---------------------------------------------------------------- +' This file is released under the MIT License +' +' Copyleft (k) 2023 +' by Juan Segura (a.k.a. Duefectu) +' +' Memory bank switch tools +' ---------------------------------------------------------------- + +#ifndef __LIBRARY_MEMORYBANK__ + +REM Avoid recursive / multiple inclusion + +#define __LIBRARY_MEMORYBANK__ + + +' ---------------------------------------------------------------- +' Place the bank indicated by bankNumber in the memory slot +' between $c000 and $ffff and updates the system variable BANKM. +' Only works on 128K and compatible models. +' Danger: If our program exceeds the address $c000 it may cause +' problems, use this function at your own risk. +' Parameters: +' bankNumber (UByte): Bank number to place at $c000 +' ---------------------------------------------------------------- +SUB FASTCALL SetBank(bankNumber AS UByte) +ASM + ; A = bankNumber to place at $c000 + ld d,a ; D = bankNumber + ld a,($5b5c) ; Read BANKM system variable + and %11111000 ; Reset bank bits + or d ; Set bank bits to bankNumber + ld bc,$7ffd ; Memory Bank control port + di ; Disable interrupts + ld ($5b5c),a ; Update BANKM system variable + out (c),a ; Set the bank + ei ; Enable interrupts +END ASM +END SUB + + +' ---------------------------------------------------------------- +' Returns the memory bank located at $c000 based on the system +' variable BANKM. +' Only works on 128K and compatible models. +' Returns: +' UByte: Bank number placed at $c000 +' ---------------------------------------------------------------- +FUNCTION FASTCALL GetBank() AS UByte + RETURN PEEK $5b5c bAND %111 +END FUNCTION + + +' ---------------------------------------------------------------- +' Place the bank indicated by bankNumber in the memory slot +' between $c000 and $ffff, copy the contents to $8000-$bfff and +' restore the bank that was at $c000 before you started. +' Only works on 128K and compatible models. +' Danger: The contents of memory located between $8000 and $bfff +' are lost, and if our program exceeds the address $8000 it may +' cause problems, use this function at your own risk. +' Parameters: +' bankNumber (UByte): Bank number to place at $8000 +' ---------------------------------------------------------------- +SUB SetCodeBank(bankNumber AS UByte) + DIM b AS UByte + + b = GetBank() + SetBank(bankNumber) + +ASM + ; Copy from $c000-$ffff to $8000-$bfff + ld hl,$c000 + ld de,$8000 + ld bc,$4000 + ldir +END ASM + + SetBank(b) +END SUB + +#endif