Skip to content

Feature/banking library #978

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion docs/library.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
<br /> Library to access RAM banks and get advantage of extra RAM in 128k models.

#### Compression / Decompression Library

* [megaLZDepack.bas](library/megalz.bas.md)
<br /> Routine wrapping the megaLZ decompression algorithm.
Expand Down
28 changes: 28 additions & 0 deletions docs/library/memorybank.md
Original file line number Diff line number Diff line change
@@ -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)
53 changes: 53 additions & 0 deletions docs/library/memorybank/getbank.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# GetBank

## Syntax

```
#include <memorybank.bas>

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)
52 changes: 52 additions & 0 deletions docs/library/memorybank/setbank.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# SetBank

## Syntax

```
#include <memorybank.bas>

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 <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
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)
65 changes: 65 additions & 0 deletions docs/library/memorybank/setcodebank.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# SetCodeBank

## Syntax

```
#include <memorybank.bas>

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 <memorybank.bas>

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)
81 changes: 81 additions & 0 deletions examples/memory_banking.bas
Original file line number Diff line number Diff line change
@@ -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
82 changes: 82 additions & 0 deletions src/lib/arch/zx48k/stdlib/memorybank.bas
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
' ----------------------------------------------------------------
' This file is released under the MIT License
'
' Copyleft (k) 2023
' by Juan Segura (a.k.a. Duefectu) <http://zx.duefectucorp.com>
'
' 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
Loading