├── .gitignore ├── LICENSE ├── README.md ├── firmware ├── TASM80.TAB ├── beastos │ ├── README.md │ ├── TASM80.TAB │ ├── bios.asm │ ├── bios.inc │ ├── bios_rtc.asm │ ├── monitor.asm │ ├── monitor_dates.asm │ ├── monitor_rtc.asm │ ├── shared_data.asm │ ├── videobeast.asm │ └── ymodem.asm ├── boot_seq.asm ├── build.bat ├── build │ ├── README.md │ ├── bios_1_6.inc │ ├── bootdisk_p25.img │ ├── firmware_p24.bin │ ├── firmware_p25.bin │ ├── flash.glob │ ├── flash_v1.3.bin │ ├── flash_v1.4.bin │ ├── flash_v1.6.bin │ └── monitor.inc ├── cpm │ ├── blank_disk.img │ ├── cpm22.asm │ ├── cpm22.bin │ └── microbeast.img ├── diskdefs ├── disp.asm ├── firmware.asm ├── flash.asm ├── font.asm ├── hex2inc.py ├── i2c.asm ├── io.asm ├── memory_test.asm ├── ports.asm ├── rtc.asm ├── shared_data.asm ├── uart.asm └── utils │ ├── README.md │ ├── cushion.ch8 │ ├── download.asm │ ├── download.com │ ├── insigbyt.ch8 │ ├── restore.asm │ ├── restore.com │ ├── upload.com │ ├── vload.asm │ ├── vload.com │ ├── vpeek.asm │ ├── vpeek.com │ ├── write.asm │ ├── write.com │ ├── z80asm (SLR Systems).pdf │ └── z80asm.com ├── reference ├── 16c550.pdf ├── MCP7940N_RTC.pdf └── z80piomn.pdf └── src └── examples ├── flash.asm ├── i2c.asm ├── manicminer ├── README.md ├── carton.asm ├── microbeast.asm ├── microbeast.inc └── mm.asm ├── ports.asm ├── snes.asm ├── uart.asm ├── videobeast ├── mandelbrot_benchmark.asm └── mandelbrot_benchmark.png └── ymodem.asm /.gitignore: -------------------------------------------------------------------------------- 1 | # Temporary files 2 | *.000 3 | *.bak 4 | *.bck 5 | *~ 6 | _autosave-* 7 | *.tmp 8 | 9 | # Output 10 | *.zip 11 | *.obj 12 | *.lst 13 | 14 | # Visual studio 15 | *.pdb 16 | .vs 17 | Debug 18 | Backup 19 | Release 20 | *.exe 21 | *.vcxproj* -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 atoone 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MicroBeast 2 | A self contained 8-bit Z80 computer kit with a unique 14 segment LED display. 3 | 4 | ![microbeast](https://user-images.githubusercontent.com/5371724/222550946-2ff28e32-867d-42ff-b07e-517b6456cc09.jpg) 5 | 6 | # Introduction 7 | 8 | MicroBeast is a kit you can build yourself. This repository provides information about the system, useful code and downloads. 9 | 10 | Visit the Wiki for technical documentation: https://github.com/atoone/MicroBeast/wiki 11 | 12 | More details on the project can be found at https://feertech.com/microbeast/ 13 | 14 | # Specs 15 | 16 | | | Specs | 17 | |-----------|---------------| 18 | | CPU | 8/10Mhz Z80 | 19 | | ROM | 512K Flash Rom | 20 | | RAM | 512K Ram | 21 | | Display | 24 character, 14 segment LEDs | 22 | | Comms | Serial over USB C | 23 | | Keyboard | 47 keys | 24 | | Power | USB-C, or 3-5v barrel connector | 25 | | I/O | 12 Pins GPIO / I2C bus / RC2014 expansion header | 26 | | | Battery backed RTC | 27 | | | 1-bit audio | 28 | | Size | 235mm x 160mm x 35mm | 29 | -------------------------------------------------------------------------------- /firmware/beastos/README.md: -------------------------------------------------------------------------------- 1 | # MicroBeast Simple Operating System 2 | 3 | This project provides a boot Monitor utility and Basic CP/M 2.2 implementation for MicroBeast. 4 | 5 | ## Overview 6 | 7 | Key files: 8 | 9 | * cpm22.asm - Standard CP/M 2.2 CCP and BDOS source code (single combined executable) 10 | * bios.asm - MicroBeast specific BIOS routines 11 | * monitor.asm - Boot Monitor (combines Monitor and BIOS) 12 | 13 | In a standard CP/M installation, the machine-specific BIOS is installed at the top of system memory to provide access to display, I/O and other hardware. The BIOS then 14 | loads the CCP (Command control processor) and BDOS (Basic Disc Operating System) just below itself from a suitable source (e.g. boot sectors of a floppy drive). 15 | 16 | MicroBeast provides a boot Monitor that, combined with the CP/M compatible BIOS, is installed by the ROM-resident firmware on startup. The monitor resides just below the 17 | BIOS, and accesses its functions directly for display, I/O and keyboard. The user can easily select between booting to the monitor, or starting CP/M normally - at which 18 | point the BIOS will overwrite the Monitor with the CP/M CCP and BDOS. 19 | 20 | The BIOS has the standard CP/M 2.2 entry jump table, but may provide additional routines that can be called directly by the monitor. 21 | 22 | ``` 23 | 24 | Monitor CP/M 25 | 26 | 0xFFFF +--------------------------+ +--------------------------+ 27 | | BIOS Stack | | BIOS Stack | 28 | | | | | 29 | 0xFF00 | BIOS Work area | | BIOS Work area | 30 | +--------------------------+ +--------------------------+ 31 | | | | | 32 | 0xFE00 | Interrupt 2 Vector table | | Interrupt 2 Vector table | 33 | +--------------------------+ +--------------------------+ 34 | 0xFDFD | Interrupt Jump | | Interrupt Jump | 35 | | | | | 36 | | | | | 37 | 0xEA00 | BIOS | 0xEA00 | BIOS | 38 | +--------------------------+ +--------------------------+ 39 | | | | | 40 | | | | | 41 | | | 0xDC00 | BDOS | 42 | 0xDB00 | Monitor | +--------------------------+ 43 | +--------------------------+ | | 44 | | | | | 45 | | | 0xD400 | CCP | 46 | | | +--------------------------+ 47 | | | | | 48 | | | | | 49 | . . . . 50 | . . . . 51 | | | | | 52 | | | | | 53 | | | 0x0100 | Transient Program Area | 54 | | | +--------------------------+ 55 | | | | Low Storage | 56 | 0x0000 +--------------------------+ 0x0000 +--------------------------+ 57 | 58 | ``` 59 | 60 | As standard with CP/M 2.2, the BIOS is expected to be `0x1600` (5632 decimal) bytes above the base of the CCP. At present, the BIOS takes up `0x1600` (5632 decimal) bytes. The interrupt jump and vector table with the BIOS work area above them take up just over 512 bytes, leaving 5120 bytes available for BIOS routines. These handle Flash I/O, the 14 segment display, I2C and RTC communications. 61 | 62 | ## Console handling 63 | 64 | The console is a virtual VT-52 terminal, with 40 x 24 characters by default (columns x rows). This is stored in a page in memory that itself represents 65 | a virtual screen text display 128 x 64, with two bytes being stored for each character (ASCII code and colour attribute). The virtual screen occupies exactly 66 | one page of memory (16K), as each of the 64 rows occupies 256 bytes. It is treated as wrapping at row 64. Whilst this appears inefficient, it means that 67 | addressing is simple (row is high byte of address, column x 2 is low byte), and scrolling of the virtual console can be achieved by adjusting the offset of 68 | the virtual console within the screen buffer. 69 | 70 | The console is controlled by the IOByte, allowing input and output to be selected using the standard CP/M `STAT` command. To view the current IOByte 71 | configuration use `STAT DEV:` which will display something like: 72 | 73 | ``` 74 | CON: is CRT: 75 | RDR: is TTY: 76 | PUN: is TTY: 77 | LST: is TTY: 78 | ``` 79 | 80 | This shows which devices are allocated to the `CON` (Console - normal input and output), `RDR` Reader device, `PUN` Punched card input and output for the `LST` list device. 81 | 82 | 83 | Note that the `TTY` and `CRT` options for the console device only control the input source - any output will be directed to *both* the built in display *and* the UART serial device. To send output 84 | to a single destination, use the `BAT` option, which specifies that the input is determined by the `RDR` Reader device, and ouput by the `LST` list device. 85 | 86 | The `STAT` command can be used to change the IOByte configuration. For instance, to switch input to be from Serial (TTY) and output to be display + serial, us `STAT CON:=TTY:`. 87 | 88 | The IOByte is a single byte at address `03h` in RAM, with the following bitmap. 89 | ``` 90 | +-----+-----+-----+-----+-----+-----+-----+-----+ 91 | | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 92 | +-----+-----+-----+-----+-----+-----+-----+-----+ 93 | | LST | PUN | RDR | CON | 94 | +-----+-----+-----+-----+-----+-----+-----+-----+ 95 | ``` 96 | 97 | 98 | Con: 99 | 00 TTY - Input on TTY, output to display + tty 100 | 01 CRT - Input on Keyboard, output to display + tty 101 | 10 BAT - Use Reader for console input, and the current List (printer) device as the console output. 102 | 11 UC1 - Reserved for Phase 2 103 | Rdr: 104 | 00 TTY - Input on TTY 105 | 01 PTR - Input on keyboard 106 | 10 UR1 - Unused 107 | 11 UR2 - Unused 108 | PUN: 109 | 00 TTY - Output to TTY 110 | 01 PTP - Unused 111 | 10 UP1 - Unused 112 | 11 UP2 - Unused 113 | LST: 114 | 00 TTY - Output to TTY 115 | 01 CRT - Output to display 116 | 10 LPT - Unused 117 | 11 UL1 - Reserved for Phase 2 118 | 119 | 120 | ## Escape Codes 121 | 122 | The console supports the following escape character sequences: 123 | 124 | | Characters | Description | 125 | |--------------|-----------------------------------------------------| 126 | | `ESC` `K` | Clear to end of line | 127 | | `ESC` `J` | Clear to end of screen 128 | | `ESC` `A` | Cursor up one line | 129 | | `ESC` `B` | Cursor down one line | 130 | | `ESC` `C` | Cursor right one character | 131 | | `ESC` `D` | Cursor left one character | 132 | | `ESC` `Y` | Set cursor position, next two chars are X and Y + 32 | 133 | | `ESC` `b` | Set foreground (ink) colour. Next char is colour + 31 | 134 | 135 | 136 | (This section is incomplete - more will be added soon) 137 | 138 | 139 | ## Disk Handling 140 | 141 | ### Rom Disk 142 | 143 | Disks are 248K in size, 79 tracks of 26 sectors, with the first 2 tracks containing the CP/M operating system 144 | 145 | The ROM disk takes up 16 pages, from page 4 146 | 147 | The RAM disk takes up 16 pages, from page 0x25 (37 decimal) 148 | 149 | When MicroBeast starts up, the Monitor formats a blank RAM disk. RAM disks can be saved and loaded from the Flash ROM using 150 | the `WRITE.COM` and `RESTORE.COM` utilities on the boot disk. 151 | 152 | ### Utilities 153 | 154 | The default disk contains a number of utilities, including: 155 | 156 | `write.com` - Writes the current RAM disk image to the upper half of Flash ROM (256K, or page 0x10h onwards) 157 | `restore.com` - Restores the Flash ROM disk image to the RAM disk 158 | `download.com` - Grant Searl's utility for receiving files over the console (http://searle.x10host.com/cpm/index.html) 159 | `upload.com` - The companion to `download.com` by Peacock Media (https://github.com/RC2014Z80/RC2014/tree/master/CPM/UPLOAD.COM) 160 | `vpeek.com` - Allows VideoBeast memory and registers to be examined and updated 161 | 162 | ## Building 163 | 164 | The core firmware can be built using the following commands: 165 | 166 | ``` 167 | cd beastos 168 | tasm -t80 monitor.asm 169 | python ..\hex2inc.py monitor.obj 170 | cd .. 171 | tasm -t80 -b firmware.asm build\firmware_p25.bin 172 | ``` 173 | 174 | ## Running 175 | 176 | After building, the current version can be run from within the Beast Emulator with a command such as: 177 | 178 | `beast -f 0 firmware\build\firmware_p25.bin -l 0 firmware\firmware.lst -l 23 firmware\beastos\monitor.lst -f 10000 firmware\build\bootdisk_p25.img` 179 | 180 | ## Build CP/M 181 | 182 | If the base address of CP/M needs to change, the CCP source must be rebuilt. From the firmware directory, run: 183 | 184 | `tasm -t80 -b cpm\cpm22.asm cpm\cpm22.bin` 185 | 186 | Then build the disk image using the following: 187 | 188 | ## CP/M Disk Image 189 | 190 | Using CPM Tools, Create a blank disk with the CP/M CCP in the first sectors (note a valid diskdefs file is provided in the firmware directory) : 191 | 192 | `mkfs.cpm.exe -f memotech-type50 -b cpm22.bin microbeast.img` 193 | 194 | Add files to the image: 195 | 196 | `cpmcp.exe -f memotech-type50 microbeast.img mbasic.com 0:mbasic.com` 197 | 198 | List files on the image 199 | 200 | `cpmls.exe -f memotech-type50 microbeast.img` -------------------------------------------------------------------------------- /firmware/beastos/bios.inc: -------------------------------------------------------------------------------- 1 | ; 2 | ; MicroBeast BIOS.inc 3 | ; 4 | ; Include file for the MicroBeast BIOS Jump table and CP/M BIOS calls 5 | ; 6 | ; For BIOS version 1.6+ 7 | ; 8 | 9 | ; 10 | ; CP/M BDOS 2.2 call vectors. CALL BDOS with C set to one of the following values 11 | ; Reference: http://www.gaby.de/cpm/manuals/archive/cpm22htm/ch5.htm 12 | ; 13 | BDOS .EQU 00005h 14 | 15 | BDOS_RESET .EQU 00h 16 | BDOS_CONIN .EQU 01h 17 | BDOS_CONOUT .EQU 02h 18 | BDOS_READIN .EQU 03h 19 | BDOS_PUNCHOUT .EQU 04h 20 | BDOS_LISTOUT .EQU 05h 21 | BDOS_CONIO .EQU 06h 22 | BDOS_GETIOBYTE .EQU 07h 23 | BDOS_SETIOBYTE .EQU 08h 24 | BDOS_PRINTSTRING .EQU 09h 25 | BDOS_READBUFFER .EQU 0Ah 26 | BDOS_CONSOLESTATUS .EQU 0Bh 27 | BDOS_GETVERSION .EQU 0Ch 28 | BDOS_RESETDISK .EQU 0Dh 29 | BDOS_SELECTDISK .EQU 0Eh 30 | BDOS_OPENFILE .EQU 0Fh 31 | BDOS_CLOSEFILE .EQU 10h 32 | BDOS_SEARCHFIRST .EQU 11h 33 | BDOS_SEARCHNEXT .EQU 12h 34 | BDOS_DELETEFILE .EQU 13h 35 | BDOS_READSEQ .EQU 14h 36 | BDOS_WRITESEQ .EQU 15h 37 | BDOS_MAKEFILE .EQU 16h 38 | BDOS_RENAMEFILE .EQU 17h 39 | BDOS_GETLOGINVECTOR .EQU 18h 40 | BDOS_GETCURRENTDISK .EQU 19h 41 | BDOS_SETDMAADDRESS .EQU 1Ah 42 | BDOS_GETALLOCVECTOR .EQU 1Bh 43 | BDOS_WRITEPROTECT .EQU 1Ch 44 | BDOS_GETREADONLYVEC .EQU 1Dh 45 | BDOS_SETFILEATTR .EQU 1Eh 46 | BDOS_GETDISKPARAMS .EQU 1Fh 47 | BDOS_GETUSERCODE .EQU 20h 48 | BDOS_READRANDOM .EQU 21h 49 | BDOS_WRITERANDOM .EQU 22h 50 | BDOS_GETFILESIZE .EQU 23h 51 | BDOS_SETRANDOMRECORD .EQU 24h 52 | BDOS_RESETDRIVE .EQU 25h 53 | BDOS_WRITERANDOMZERO .EQU 26h 54 | 55 | 56 | ; 57 | ; Direct access to bios entrypoints - use at own risk 58 | ; 59 | BIOS_START .EQU 0EA00h ; If (WHEN) the BIOS start address changes, this will be invalidated 60 | 61 | BIOS_BOOT .EQU BIOS_START 62 | BIOS_WBOOT .EQU BIOS_START+003h 63 | BIOS_CONIST .EQU BIOS_START+006h ; Console status - Return A = 0FFH if character ready, 00H if not 64 | BIOS_CONIN .EQU BIOS_START+009h ; Console input - Wait for input, returning character in A 65 | BIOS_CONOUT .EQU BIOS_START+00Ch ; Console OUTput - Write character in C to console 66 | BIOS_LIST .EQU BIOS_START+00Fh ; List device OUTput 67 | BIOS_PUNCH_OUT .EQU BIOS_START+012h ; Punch card device OUTput 68 | BIOS_READ_IN .EQU BIOS_START+015h ; Card Reader input 69 | BIOS_DSK_HOME .EQU BIOS_START+018h ; Home disk 70 | BIOS_DSK_SELECT .EQU BIOS_START+01Bh ; Select disk 71 | BIOS_DSK_TRACK .EQU BIOS_START+01Eh ; Select track 72 | BIOS_DSK_SECTOR .EQU BIOS_START+021h ; Select sector 73 | BIOS_DSK_DMA .EQU BIOS_START+024h ; Set DMA ADDress 74 | BIOS_DSK_READ .EQU BIOS_START+027h ; Read 128 bytes 75 | BIOS_DSK_WRITE .EQU BIOS_START+02Ah ; Write 128 bytes 76 | BIOS_LIST_STATUS .EQU BIOS_START+02Dh ; List status 77 | BIOS_SECTOR_TRANSLATE .EQU BIOS_START+030h ; Sector translate 78 | 79 | 80 | ; 81 | ; MicroBeast BIOS Specific routines. These are placed at the end of the BIOS and should(!) be fixed for direct calls. 82 | ; 83 | ; 84 | 85 | 86 | ; 87 | ; CALL MBB_GET_VERSION - Get the current BIOS version 88 | ; Returns: A = Major, minor version in upper, lower nibble. e.g. 016h = version 1.6 89 | ; 90 | MBB_GET_VERSION .EQU 0FDFAh 91 | 92 | ; 93 | ; CALL MBB_PLAY_NOTE - Play a note on the speaker 94 | ; Parameters: 95 | ; D = Octave 2-6 96 | ; E = Note 0-11 97 | ; C = 1-15 duration, ~tenths of a second 98 | ; 99 | MBB_PLAY_NOTE .EQU 0FDF7h 100 | 101 | ; 102 | ; CALL MBB_WAIT_KEY - Waits for until a key is pressed and released 103 | ; 104 | MBB_WAIT_KEY .EQU 0FDF4h 105 | 106 | ; 107 | ; CALL MBB_I2C_RD_ADDRESS - Read a byte from device, with address. i2c_stop is not called. 108 | ; Parameters: 109 | ; H = Device ID 110 | ; L = Address 111 | ; Returns: 112 | ; A = Byte read 113 | ; Carry SET if success. 114 | ; 115 | MBB_I2C_RD_ADDRESS .EQU 0FDF1h 116 | 117 | ; 118 | ; CALL MBB_I2C_WR_ADDRESS - Start writing to a device, with address. i2c_stop is not called. 119 | ; Parameters: 120 | ; H = Device ID 121 | ; L = Address 122 | ; Returns: 123 | ; Carry SET if success. 124 | ; 125 | MBB_I2C_WR_ADDRESS .EQU 0FDEEh 126 | 127 | ; 128 | ; CALL MBB_I2C_READ - Read a byte from current device, without ACK. 129 | ; Returns: 130 | ; A = Byte read 131 | ; 132 | MBB_I2C_READ .EQU 0FDEBh 133 | 134 | ; 135 | ; CALL MBB_I2C_WRITE - Write a byte to current device. i2c_stop is not called. 136 | ; Parameters: 137 | ; A = Byte to write 138 | ; Returns: 139 | ; Carry SET if success. 140 | ; 141 | MBB_I2C_WRITE .EQU 0FDE8h 142 | 143 | ; 144 | ; CALL MBB_I2C_STOP - Send I2C Stop sequence 145 | ; 146 | MBB_I2C_STOP .EQU 0FDE5h 147 | 148 | ; 149 | ; CALL MBB_I2C_START - Send I2C Start sequence 150 | ; 151 | MBB_I2C_START .EQU 0FDE2h 152 | 153 | ; 154 | ; CALL MBB_SET_PAGE - Set page mapping 155 | ; Parameters: 156 | ; A = Logical (CPU) page to set (0-2) 157 | ; E = Physical page (00-1F: ROM 20-3F: RAM) 158 | ; 159 | MBB_SET_PAGE .EQU 0FDDFh 160 | 161 | ; 162 | ; CALL MBB_GET_PAGE - Get page mapping 163 | ; Parameters: 164 | ; C = Logical (CPU) page to get (0-2) 165 | ; Returns 166 | ; A = Physical page (00-1F: ROM 20-3F: RAM), or 0FFH for error 167 | ; 168 | MBB_GET_PAGE .EQU 0FDDCh 169 | 170 | ; 171 | ; CALL MBB_PRINT - Print following inline text, zero terminated 172 | ; .DB "Test to print", 0 173 | ; 174 | MBB_PRINT .EQU 0FDD9h 175 | 176 | ; 177 | ; CALL MBB_WRITE_LED - Directly write bitmask to LED display (Check Font editor online for bit order) 178 | ; Parameters: 179 | ; HL = Bit pattern to write to LED digit 180 | ; A = Column (0-23) 181 | ; 182 | MBB_WRITE_LED .EQU 0FDD6h 183 | 184 | ; 185 | ; CALL MBB_LED_BRIGHTNESS - Set segments in digit A to brightness C 186 | ; Parameters: 187 | ; A = Column (0-23) 188 | ; C = Brightness (0-128) 189 | ; 190 | MBB_LED_BRIGHTNESS .EQU 0FDD3h 191 | 192 | ; 193 | ; CALL MBB_RTC_TIME - Get the current time from the RTC 194 | ; Parameters: 195 | ; HL = Address of 7 byte time data block to store current time 196 | ; Returns: 197 | ; Carry SET if success 198 | ; 199 | ; Time Data block 200 | ; HL -> Seconds - 2 digits BCD 201 | ; HL+1 -> Minutes - 2 digits BCD 202 | ; HL+2 -> Hour - 24hr clock, 2 digits BCD 203 | ; HL+3 -> Weekday (1-7. Monday=1) 204 | ; HL+4 -> Day 1-31, 2 digits BCD 205 | ; HL+5 -> Month 1-12, 2 digits BCD 206 | ; HL+6 -> Year, 2 digits BCD 207 | ; 208 | MBB_RTC_TIME .EQU 0FDD0h 209 | 210 | ; CALL MBB_GET_DRIVE_PAGE - Get the page in memory being used as the base for the drive selected by A 211 | ; Parameters: 212 | ; A = Drive number 0, 1 213 | ; Returns: 214 | ; A = Page in ROM/RAM for the given drive 215 | ; or A = 0 if the selected drive is not supported. 216 | ; 217 | MBB_GET_DRIVE_PAGE .EQU 0FDCDh 218 | 219 | ; CALL MBB_FLASH_WRITE - Erase and write flash data. Data is written to 4K sectors, which are erased 220 | ; before writing. This uses Page 0 to write the data, so the source must be above 3FFFh 221 | ; Data is written from the start of the specified 4K sector 222 | ; Note: This means if BC is an exact multiple of sector size, D is returned as the previous sector 223 | ; 224 | ; Parameters: 225 | ; D -> 7 bit index of 4K sector being written 226 | ; HL -> Address of source data 227 | ; BC -> bytes to write 228 | ; Returns: 229 | ; D pointing to last sector written 230 | ; 231 | MBB_FLASH_WRITE .EQU 0FDCAh 232 | 233 | ; CALL MBB_SET_USR_INT - Set or query the user interrupt. 234 | ; The specified routine will be called after keyboard polling, every 60th of a second. The shadow register 235 | ; set is selected before the call (EXX), and AF is preserved. The routine should RETurn normally. 236 | ; Interrupt routines survive warm reboots, but no special measures are taken to ensure the memory they 237 | ; occupy is preserved. 238 | ; 239 | ; Parameters: 240 | ; HL = Address of user interrupt routine, or zero to disable. Call with 0FFFFh to query the current value 241 | ; Returns: 242 | ; The address of the current user interrupt routine, or zero if none is configured. 243 | ; 244 | MBB_SET_USR_INT .EQU 0FDC7h 245 | 246 | -------------------------------------------------------------------------------- /firmware/beastos/bios_rtc.asm: -------------------------------------------------------------------------------- 1 | ; RTC Routines 2 | ; 3 | ; 4 | ; Copyright (c) 2023 Andy Toone for Feersum Technology Ltd. 5 | ; 6 | ; Part of the MicroBeast Z80 kit computer project. Support hobby electronics. 7 | ; 8 | ; Permission is hereby granted, free of charge, to any person obtaining a copy 9 | ; of this software and associated documentation files (the "Software"), to deal 10 | ; in the Software without restriction, including without limitation the rights 11 | ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | ; copies of the Software, and to permit persons to whom the Software is 13 | ; furnished to do so, subject to the following conditions: 14 | ; 15 | ; The above copyright notice and this permission notice shall be included in all 16 | ; copies or substantial portions of the Software. 17 | ; 18 | ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | ; SOFTWARE. 25 | ; 26 | ; 27 | .MODULE rtc 28 | 29 | ; Set the initial time and start the clock 30 | ; 31 | ; 32 | rtc_init CALL m_print_inline 33 | .DB "\n\rCheck RTC",0 34 | 35 | CALL _read_seconds 36 | CALL _pause 37 | BIT 7, E ; Check to see if the clock is running 38 | RET NZ ; Return if it is.. 39 | 40 | _do_reset CALL m_print_inline 41 | .DB "\n\rReset RTC",0 42 | 43 | LD H, RTC_ADDRESS ; Clock isn't running, reset to default time 44 | LD L, RTC_REG_SEC 45 | CALL i2c_write_to 46 | JP NC, rtc_ack_error 47 | 48 | LD HL, time_scratch 49 | _reset_loop LD A, (HL) 50 | INC HL 51 | CP 0ffh 52 | JP Z, _start_clock 53 | CALL i2c_write 54 | JP NC, rtc_ack_error 55 | JR _reset_loop 56 | 57 | _start_clock CALL i2c_stop ; Enable VBAT and start the clock 58 | 59 | LD H, RTC_ADDRESS ; Enable VBAT 60 | LD L, RTC_REG_WKDAY 61 | CALL i2c_read_from 62 | JP NC, rtc_ack_error 63 | LD E, A 64 | CALL i2c_stop 65 | SET 3, E 66 | CALL _pause 67 | 68 | CALL i2c_write_to 69 | JP NC, rtc_ack_error 70 | LD A, E 71 | CALL i2c_write 72 | JP NC, rtc_ack_error 73 | CALL i2c_stop 74 | 75 | CALL _read_seconds 76 | SET 7, E ; Set bit 7 to enable clock 77 | 78 | CALL i2c_write_to 79 | JP NC, rtc_ack_error 80 | LD A, E 81 | CALL i2c_write 82 | JP NC, rtc_ack_error 83 | CALL i2c_stop 84 | RET 85 | 86 | _pause LD B, 0 87 | DJNZ $ 88 | RET 89 | 90 | ; 91 | ; Read seconds register in E 92 | ; 93 | _read_seconds LD H, RTC_ADDRESS 94 | LD L, RTC_REG_SEC 95 | CALL i2c_read_from 96 | JP NC, rtc_ack_error 97 | LD E, A 98 | JP i2c_stop 99 | 100 | rtc_ack_error CALL i2c_stop 101 | 102 | CALL m_print_inline 103 | .DB "\n\rRTC Panic",0 104 | RET 105 | 106 | ; 107 | ; Read the time to the 7 bytes starting at HL 108 | ; Returns with Carry SET if successful, else Carry CLEAR 109 | ; 110 | rtc_get_time_hl PUSH HL 111 | LD H, RTC_ADDRESS 112 | LD L, RTC_REG_SEC 113 | CALL i2c_read_from 114 | POP BC 115 | RET NC 116 | LD HL, _masktable 117 | JR _store_time 118 | _get_loop PUSH BC 119 | CALL i2c_ack 120 | CALL i2c_read 121 | POP BC 122 | _store_time AND (HL) 123 | LD (BC), A 124 | INC HL 125 | INC BC 126 | LD A, (HL) 127 | AND A 128 | JR NZ, _get_loop 129 | CALL i2c_stop 130 | SCF 131 | RET 132 | 133 | _masktable .db 07fh ; Seconds 134 | .db 07fh ; Minutes 135 | .db 03fh ; Hours 136 | .db 007h ; Weekday 137 | .db 03Fh ; Date 138 | .db 01fh ; Month 139 | .db 0ffh ; Year 140 | .db 000h ; End of mask marker 141 | 142 | 143 | ; Initial time on power up.. 144 | time_scratch .db 23h ; Seconds 145 | .db 59h ; Minutes 146 | .db 08h ; Hours (24 hr clock) 147 | .db 06h ; Weekday (1-7. Monday=1) 148 | .db 05h ; Date 149 | .db 11h ; Month 150 | .db 22h ; Year 151 | .db 0ffh ; 0ffh end marker 152 | 153 | .MODULE main 154 | -------------------------------------------------------------------------------- /firmware/beastos/monitor_dates.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; Copyright (c) 2023 Andy Toone for Feersum Technology Ltd. 3 | ; 4 | ; Part of the MicroBeast Z80 kit computer project. Support hobby electronics. 5 | ; 6 | ; Permission is hereby granted, free of charge, to any person obtaining a copy 7 | ; of this software and associated documentation files (the "Software"), to deal 8 | ; in the Software without restriction, including without limitation the rights 9 | ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | ; copies of the Software, and to permit persons to whom the Software is 11 | ; furnished to do so, subject to the following conditions: 12 | ; 13 | ; The above copyright notice and this permission notice shall be included in all 14 | ; copies or substantial portions of the Software. 15 | ; 16 | ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | ; SOFTWARE. 23 | ; 24 | 25 | set_date LD A, (cursor_row) 26 | ADD A, 31 27 | LD (_set_date_row), A 28 | LD (_set_week_row), A 29 | CALL m_print_inline 30 | .DB CARRIAGE_RETURN, "Date YY/MM/DD", ESCAPE_CHAR, "K", ESCAPE_CHAR, "Y", 31 | _set_date_row .DB 0 32 | .DB 31+6, 0 33 | LD HL, date_limits 34 | CALL get_date_time 35 | 36 | LD A, 1 37 | _select_loop LD (day_of_week), A 38 | 39 | CALL m_print_inline 40 | .DB ESCAPE_CHAR, "Y", 41 | _set_week_row .DB 0 42 | .DB 31+16, 0 43 | 44 | LD A, (day_of_week) 45 | LD B, A 46 | LD HL, weekdays 47 | _week_loop DJNZ _next_week 48 | 49 | _print_week LD A, (HL) 50 | INC HL 51 | AND A 52 | JR Z, _select_week 53 | CALL m_print_a_safe 54 | JR _print_week 55 | 56 | _next_week LD A, (HL) 57 | INC HL 58 | AND A 59 | JR NZ, _next_week 60 | JR _week_loop 61 | 62 | _select_week CALL bios_conist 63 | AND A 64 | JR Z, _select_week 65 | CALL bios_conin 66 | CP KEY_UP 67 | JR NZ, _test_down 68 | LD A, (day_of_week) 69 | CP 7 70 | JR Z, _select_week 71 | INC A 72 | JR _select_loop 73 | _test_down CP KEY_DOWN 74 | JR NZ, _test_enter 75 | LD A, (day_of_week) 76 | CP 1 77 | JR Z, _select_week 78 | DEC A 79 | JR _select_loop 80 | _test_enter CP KEY_ENTER 81 | JR NZ, _select_week 82 | 83 | DI 84 | LD H, RTC_ADDRESS 85 | LD L, RTC_REG_WKDAY 86 | CALL i2c_write_to 87 | JP NC, _clock_error 88 | 89 | LD HL, day_of_week 90 | LD A, (HL) 91 | INC HL 92 | 93 | OR RTC_WEEKDAY_RUNNING 94 | CALL i2c_write 95 | JP NC, _clock_error 96 | 97 | _write_date_loop LD B, (HL) 98 | INC HL 99 | 100 | LD A, (HL) 101 | INC HL 102 | SLA A 103 | SLA A 104 | SLA A 105 | SLA A 106 | 107 | OR B 108 | CP 0ffh 109 | JP Z, _start_clock 110 | CALL i2c_write 111 | JP NC, _clock_error 112 | JR _write_date_loop 113 | 114 | _start_clock CALL i2c_stop 115 | EI 116 | RET 117 | 118 | _clock_error CALL i2c_stop 119 | EI 120 | CALL m_print_inline 121 | .DB CARRIAGE_RETURN, "RTC Error", ESCAPE_CHAR, "K", 0 122 | JP bios_conin 123 | 124 | set_time LD A, (cursor_row) 125 | ADD A, 31 126 | LD (_set_time_row), A 127 | CALL m_print_inline 128 | .DB CARRIAGE_RETURN, "Time HH/mm/ss", ESCAPE_CHAR, "K", ESCAPE_CHAR, "Y", 129 | _set_time_row .DB 0 130 | .DB 31+6, 0 131 | LD HL, time_limits 132 | CALL get_date_time 133 | 134 | LD A, (digit_values+1) 135 | OR 08h 136 | LD (digit_values+1), A 137 | CALL bios_conin 138 | 139 | DI 140 | LD H, RTC_ADDRESS 141 | LD L, RTC_REG_SEC 142 | CALL i2c_write_to 143 | JP NC, _clock_error 144 | 145 | LD HL, digit_values 146 | JR _write_date_loop 147 | 148 | time_limits .DB 9,5,9,5,3,2 149 | 150 | date_limits .DB 1,3,2,1,9,9 151 | 152 | day_of_week .DB 1 153 | digit_values .DB 0,0,0,0,0,0 154 | .DB 0FFh 155 | 156 | get_date_time LD DE, digit_values 157 | LD BC, 6 158 | LDIR 159 | DEC HL 160 | DEC DE 161 | LD B, 6 162 | 163 | _get_digit PUSH HL 164 | PUSH DE 165 | PUSH BC 166 | CALL bios_conin 167 | POP BC 168 | POP DE 169 | POP HL 170 | SUB '0' 171 | JR C, _get_digit 172 | LD C, A 173 | LD A, (DE) 174 | LD (_digit_compare+1),A 175 | CP C 176 | JR C, _get_digit 177 | 178 | LD A, C 179 | LD (DE), A 180 | ADD A,'0' 181 | CALL m_print_a_safe 182 | 183 | LD A,(DE) 184 | DEC HL 185 | DEC DE 186 | BIT 0, B 187 | JR NZ, _next_tuple 188 | _digit_compare CP 0 189 | JR Z, _next_digit 190 | LD A, 9 191 | LD (DE), A 192 | _next_digit DJNZ _get_digit 193 | RET 194 | _next_tuple CALL m_print_inline 195 | .DB ESCAPE_CHAR, 'C', 0 196 | JR _next_digit -------------------------------------------------------------------------------- /firmware/beastos/monitor_rtc.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; Copyright (c) 2023 Andy Toone for Feersum Technology Ltd. 3 | ; 4 | ; Part of the MicroBeast Z80 kit computer project. Support hobby electronics. 5 | ; 6 | ; Permission is hereby granted, free of charge, to any person obtaining a copy 7 | ; of this software and associated documentation files (the "Software"), to deal 8 | ; in the Software without restriction, including without limitation the rights 9 | ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | ; copies of the Software, and to permit persons to whom the Software is 11 | ; furnished to do so, subject to the following conditions: 12 | ; 13 | ; The above copyright notice and this permission notice shall be included in all 14 | ; copies or substantial portions of the Software. 15 | ; 16 | ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | ; SOFTWARE. 23 | ; 24 | .MODULE monitor_rtc 25 | 26 | _offset_sec .EQU 0 27 | _offset_min .EQU 1 28 | _offset_hour .EQU 2 29 | _offset_wkday .EQU 3 30 | _offset_date .EQU 4 31 | _offset_month .EQU 5 32 | _offset_year .EQU 6 33 | 34 | 35 | rtc_display_time LD HL, time_scratch 36 | CALL rtc_get_time_hl 37 | JP NC, _get_error 38 | 39 | LD C, CARRIAGE_RETURN 40 | CALL bios_conout 41 | 42 | LD A, (time_scratch+_offset_wkday) 43 | LD HL, weekdays 44 | LD C, A 45 | 46 | CALL _search_word 47 | 48 | _get_date CALL _space 49 | LD A, (time_scratch+_offset_date) 50 | CALL _two_chars_space 51 | 52 | LD A, (time_scratch+_offset_month) 53 | LD HL, _months 54 | BIT 4, A 55 | JR Z, _month_ok 56 | SUB 6 57 | _month_ok LD C,A 58 | 59 | CALL _search_word 60 | CALL _space 61 | LD A, 20h 62 | CALL _two_chars 63 | 64 | LD A, (time_scratch+_offset_year) 65 | CALL _two_chars_space 66 | 67 | LD A, (time_scratch+_offset_hour) 68 | CALL _two_chars_space 69 | 70 | LD A, (time_scratch+_offset_min) 71 | CALL _two_chars_space 72 | 73 | LD A, (time_scratch+_offset_sec) 74 | CALL _two_chars 75 | RET 76 | 77 | _two_chars_space CALL _two_chars 78 | _space LD C, ' ' 79 | JP bios_conout 80 | 81 | _two_chars LD C,A 82 | SRL A 83 | SRL A 84 | SRL A 85 | SRL A 86 | ADD A, '0' 87 | PUSH BC 88 | LD C, A 89 | CALL bios_conout 90 | POP BC 91 | LD A,C 92 | AND 0fh 93 | ADD A, '0' 94 | LD C, A 95 | JP bios_conout 96 | ; 97 | ; Search table pointed to by HL for the C'th word (1-based) 98 | ; Prints the chosen word to conout 99 | ; 100 | _search_word DEC C 101 | JR NZ, _next_char 102 | 103 | _print_word LD A, (HL) 104 | INC HL 105 | AND A 106 | RET Z 107 | LD C, A 108 | PUSH HL 109 | CALL bios_conout 110 | POP HL 111 | JR _print_word 112 | 113 | _next_char LD A, (HL) 114 | INC HL 115 | AND A 116 | JR NZ, _next_char 117 | JR _search_word 118 | 119 | 120 | weekdays .DB "Mon",0 121 | .DB "Tue",0 122 | .DB "Wed",0 123 | .DB "Thu",0 124 | .DB "Fri",0 125 | .DB "Sat",0 126 | .DB "Sun",0 127 | 128 | _months .DB "Jan",0 129 | .DB "Feb",0 130 | .DB "Mar",0 131 | .DB "Apr",0 132 | .DB "May",0 133 | .DB "Jun",0 134 | .DB "Jul",0 135 | .DB "Aug",0 136 | .DB "Sep",0 137 | .DB "Oct",0 138 | .DB "Nov",0 139 | .DB "Dec",0 140 | 141 | 142 | _get_error CALL i2c_stop 143 | CALL m_print_inline 144 | .DB "Error getting time\r\n", 0 145 | XOR A 146 | RET 147 | 148 | .MODULE main -------------------------------------------------------------------------------- /firmware/beastos/shared_data.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; Shared data - common state data for routines 3 | ; 4 | ; [] show default/initial values stored at the location 5 | ; 6 | ; Copyright (c) 2023 Andy Toone for Feersum Technology Ltd. 7 | ; 8 | ; Part of the MicroBeast Z80 kit computer project. Support hobby electronics. 9 | ; 10 | ; Permission is hereby granted, free of charge, to any person obtaining a copy 11 | ; of this software and associated documentation files (the "Software"), to deal 12 | ; in the Software without restriction, including without limitation the rights 13 | ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | ; copies of the Software, and to permit persons to whom the Software is 15 | ; furnished to do so, subject to the following conditions: 16 | ; 17 | ; The above copyright notice and this permission notice shall be included in all 18 | ; copies or substantial portions of the Software. 19 | ; 20 | ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | ; SOFTWARE. 27 | ; 28 | 29 | .ORG 0FF00h 30 | 31 | ; I2C/Port B routines 32 | port_b_mode .BLOCK 1 33 | port_b_dir .BLOCK 1 34 | port_b_data .BLOCK 1 35 | 36 | ; Display functions 37 | display_address .BLOCK 1 ; byte - I/O address of the display driver (right or left) being written to 38 | 39 | ; 40 | ; Stuff 41 | timer .BLOCK 4 ; 2 Words - counts up by 1 every 64th of a second. Rollover ~2 years. 42 | 43 | ; General I/O 44 | ; 45 | ; This MUST start with keyboard_state, and will all be reset to zero when io_init is called 46 | ; 47 | _key_state_size .EQU 8 ; 8 key rollover 48 | 49 | keyboard_state .BLOCK _key_state_size ; state buffer - 8 bytes containing raw key codes for keys currently pressed 50 | keyboard_pos .BLOCK 2 ; Internal state 51 | key_shift_state .BLOCK 1 ; Holds state of shift and control keys in bits 0 and 1 respectively 52 | control_key_pressed .BLOCK 1 ; If special control keys are pressed, they are stored here.. 53 | last_keycode .BLOCK 1 ; The last keycode that was pressed, for repeats.. 54 | key_repeat_time .BLOCK 1 ; How many poll events since the key state last changed 55 | 56 | _input_buffer_size .EQU 16 57 | input_buffer .BLOCK _input_buffer_size ; 16 byte input buffer. Note wraparound is handled by bitmasks, so don't change this length 58 | input_pos .BLOCK 1 ; Next read position in input buffer 59 | input_free .BLOCK 1 ; Next write position in input buffer 60 | input_size .BLOCK 1 ; Bytes occupied in the input buffer 61 | 62 | io_data_end .EQU input_size ; Byte after IO data block, used to reset values to zero 63 | 64 | ;------------------------------- Console output and screen data ------------------------------------------------ 65 | screen_page .BLOCK 1 ; [30?] 1 Byte, screen buffer page address 66 | screen_offset .BLOCK 1 ; [0] 1 Byte, row offset (0-63) of virtual screen in screen buffer (high byte of screen address). 67 | 68 | ; *** ROW AND COL MUST BE IN THIS ORDER - READ BY bios_conout *** 69 | display_row .BLOCK 1 ; [0] 1 Byte, current row being shown by the LED display 70 | display_col .BLOCK 1 ; [0] 1 Byte, current column being shown by the LED display - Note, 0 based 71 | 72 | ; *** ROW AND COL MUST BE IN THIS ORDER - READ BY bios_conout *** 73 | cursor_row .BLOCK 1 ; [1] 1 Byte, cursor row on virtual console. Top of page is row 1. 74 | cursor_col .BLOCK 1 ; [1] 1 Byte, cursor column on virtual console. Left of page is column 1. 75 | 76 | console_height .BLOCK 1 ; [24] 1 Byte, virtual console height (rows) 77 | console_width .BLOCK 1 ; [40] 1 byte, virtual console width (columns) 78 | 79 | console_colour .BLOCK 1 ; [0x0F] 1 Byte, current colour. Top 4 bits [7:4] are background, bottom 4 [3:0] are foreground 80 | console_flags .BLOCK 1 ; 1 Byte, bit flags for console 81 | 82 | console_timer .BLOCK 1 ; 1 Byte, used to blink cursor, clear movement indicator etc. 83 | console_escape .BLOCK 1 ; 1 Byte, escape value (0 if not received yet) 84 | console_param1 .BLOCK 1 ; 1 Byte, first character after escape (0 if not recieved yet) 85 | 86 | console_identify .BLOCK 1 ; [0] 1 Byte, indicates console identifier sequence to be returned.. 87 | 88 | CFLAGS_SHOW_CURSOR .EQU 1 ; Awaiting input - show (blink) the cursor 89 | CFLAGS_TRACK_CURSOR .EQU 2 ; LED display is tracking cursor position 90 | CFLAGS_SHOW_MOVED .EQU 4 ; Show display as being moved by user 91 | CFLAGS_ESCAPE .EQU 8 ; Escape sequence started 92 | CFLAGS_CURSOR_ON .EQU 16 ; Cursor is currently displayed 93 | CFLAGS_LED_OFF .EQU 32 ; If set, don't echo to the LED display 94 | 95 | SHOW_MOVE_DELAY .EQU 60 ; How long to show the display has been moved 96 | 97 | ;------------------------------- BIOS customisation ------------------------------------------------ 98 | 99 | drive_a_mem_page .BLOCK 1 ; First page in RAM/ROM for the Drive A image - NOTE: These values must be in order of drive number 100 | drive_b_mem_page .BLOCK 1 ; First page in RAM/ROM for the Drive B image 101 | 102 | page_0_mapping .BLOCK 1 ; Stores the user mapping for these pages, so they can be correctly restored after interrupts 103 | page_1_mapping .BLOCK 1 104 | page_2_mapping .BLOCK 1 105 | page_3_mapping .BLOCK 1 106 | 107 | ;------------------------------- BDOS variables ------------------------------------------------ 108 | ; *** TRACK AND SECTOR MUST BE IN THIS ORDER - READ BY _get_memdisc_addr *** 109 | sys_track .BLOCK 1 ; 1 Byte, Current disk track 110 | sys_sector .BLOCK 2 ; Word, current disk sector 111 | sys_dmaaddr .BLOCK 2 ; Word, DMA address - Disc will read data to this address, or write from this address 112 | sys_disk_dph .BLOCK 2 ; Word, points to current disk parameter header (DPH) 113 | sys_seldsk .BLOCK 1 ; Byte, current selected disk drive (A=0, B=1..) 114 | 115 | sys_alv0 .BLOCK 32 ; 32 bytes, allocation vector 0 (max 255 blocks) 116 | sys_alv1 .BLOCK 32 ; 32 bytes, allocation vector 1 (max 255 blocks) 117 | 118 | display_buffer .BLOCK 24*2 ; 48 byte scratch area used for composing display output (eg. rtc time display etc.) 119 | 120 | intr_stackarea .BLOCK 24 ; Interrupt handler stack 121 | intr_stack .BLOCK 2 122 | 123 | user_interrupt .BLOCK 2 ; Address of user interrupt routine, or zero 124 | 125 | ; Panic codes 126 | ; 127 | PANIC_0001 .EQU 0F001h 128 | PANIC_0002 .EQU 0F002h 129 | PANIC_0003 .EQU 0F003h 130 | PANIC_0004 .EQU 0F004h 131 | 132 | -------------------------------------------------------------------------------- /firmware/beastos/videobeast.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; VideoBeast includes for CP/M BIOS 3 | ; 4 | ; 5 | ; Copyright (c) 2023 Andy Toone for Feersum Technology Ltd. 6 | ; 7 | ; Part of the MicroBeast Z80 kit computer project. Support hobby electronics. 8 | ; 9 | ; Permission is hereby granted, free of charge, to any person obtaining a copy 10 | ; of this software and associated documentation files (the "Software"), to deal 11 | ; in the Software without restriction, including without limitation the rights 12 | ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | ; copies of the Software, and to permit persons to whom the Software is 14 | ; furnished to do so, subject to the following conditions: 15 | ; 16 | ; The above copyright notice and this permission notice shall be included in all 17 | ; copies or substantial portions of the Software. 18 | ; 19 | ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | ; SOFTWARE. 26 | ; 27 | 28 | VBASE .EQU 04000h 29 | 30 | VB_MODE .EQU VBASE + 03FFFh 31 | VB_REGISTERS_LOCKED .EQU VBASE + 03FFEh 32 | 33 | VB_PAGE_0 .EQU VBASE + 03FF9h 34 | VB_PAGE_1 .EQU VBASE + 03FF8h 35 | VB_PAGE_2 .EQU VBASE + 03FF7h 36 | VB_PAGE_3 .EQU VBASE + 03FF6h 37 | 38 | VB_LOWER_REGS .EQU VBASE + 03FF5h 39 | 40 | 41 | VB_LAYER_0 .EQU VBASE + 03F80h 42 | VB_LAYER_1 .EQU VBASE + 03F90h 43 | VB_LAYER_2 .EQU VBASE + 03FA0h 44 | VB_LAYER_3 .EQU VBASE + 03FB0h 45 | VB_LAYER_4 .EQU VBASE + 03FC0h 46 | VB_LAYER_5 .EQU VBASE + 03FD0h 47 | 48 | MODE_640 .EQU 0 49 | MODE_848 .EQU 1 50 | MODE_DOUBLE .EQU 8 51 | MODE_TESTCARD .EQU 010h 52 | 53 | MODE_MAP_16K .EQU 0 54 | MODE_MAP_SINCLAIR .EQU 080h 55 | 56 | LAYER_TYPE .EQU 0 57 | LAYER_TOP .EQU 1 58 | LAYER_BOTTOM .EQU 2 59 | LAYER_LEFT .EQU 3 60 | LAYER_RIGHT .EQU 4 61 | LAYER_SCROLL_X .EQU 5 62 | LAYER_SCROLL_XY .EQU 6 63 | LAYER_SCROLL_Y .EQU 7 64 | 65 | TYPE_NONE .EQU 0 66 | TYPE_TEXT .EQU 1 67 | TYPE_SPRITE .EQU 2 68 | TYPE_TILE .EQU 3 69 | TYPE_BITMAP_8 .EQU 4 70 | 71 | TEXT_MAP_BASE .EQU 8 ; 16Kb character map 72 | TEXT_FONT_BASE .EQU 9 ; 2Kb font offset 73 | TEXT_PALETTE .EQU 10 ; Bits 0-3: Palette number Bit 4: Use Sinclair bit pattern 74 | TEXT_BITMAP .EQU 11 ; 16Kb 1bpp bitmap.. 75 | 76 | VB_UNLOCK .EQU 0F3h ; Unlock register write 77 | 78 | VIDEOBEAST_PAGE .EQU 40h -------------------------------------------------------------------------------- /firmware/boot_seq.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; Boot sequence 3 | ; 4 | ; 5 | ; Copyright (c) 2023 Andy Toone for Feersum Technology Ltd. 6 | ; 7 | ; Part of the MicroBeast Z80 kit computer project. Support hobby electronics. 8 | ; 9 | ; Permission is hereby granted, free of charge, to any person obtaining a copy 10 | ; of this software and associated documentation files (the "Software"), to deal 11 | ; in the Software without restriction, including without limitation the rights 12 | ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | ; copies of the Software, and to permit persons to whom the Software is 14 | ; furnished to do so, subject to the following conditions: 15 | ; 16 | ; The above copyright notice and this permission notice shall be included in all 17 | ; copies or substantial portions of the Software. 18 | ; 19 | ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | ; SOFTWARE. 26 | ; 27 | .MODULE boot_sequence 28 | ; 29 | ; TODO: PIO setup should happen after the initial beep. Do it here for now, until new boards are available. 30 | ; 31 | LD A, PIO_SET_INTERRUPT ; Ports A/B Interrupt control - no interrupts 32 | OUT (PIO_A_CTRL), A ; Set control twice in case a reset interrupted a control sequence 33 | OUT (PIO_A_CTRL), A 34 | OUT (PIO_B_CTRL), A 35 | OUT (PIO_B_CTRL), A 36 | 37 | LD A, PIO_MODE_3 ; Port A Mode 3 38 | OUT (PIO_A_CTRL), A 39 | LD A, 0FFh ; All inputs 40 | OUT (PIO_A_CTRL), A 41 | 42 | 43 | LD A, PIO_MODE_3 ; Port B mode 3 44 | OUT (PIO_B_CTRL), A 45 | LD A, PORT_B_IOMASK ; All inputs, apart from bit 4 (audio out) 46 | OUT (PIO_B_CTRL), A 47 | 48 | LD HL, 0E80h ; Approx middle C 49 | ; 50 | ; Beep to show we've booted 51 | ; 52 | _boot_beep IN A, (AUDIO_PORT) ; Check the state of the audio port,, 53 | LD D, A 54 | LD E, 100 ; 100 cycles = 1/3 of a sec 55 | _beep_loop LD A, D 56 | XOR AUDIO_MASK 57 | OUT (AUDIO_PORT), A 58 | 59 | LD C, L 60 | _beep_delay0 LD B, H 61 | _beep_delay1 DJNZ _beep_delay1 ; 13 * (count-2) + 8 62 | DEC C 63 | JR NZ, _beep_delay0 64 | 65 | LD A, D 66 | OUT (AUDIO_PORT), A 67 | 68 | LD C, L 69 | _beep_delay2 LD B, H 70 | _beep_delay3 DJNZ _beep_delay3 ; 13 * (count-2) + 8 71 | DEC C 72 | JR NZ, _beep_delay2 73 | 74 | DEC E 75 | JR NZ, _beep_loop 76 | 77 | ; 78 | ; Now initialise the UART 79 | ; 80 | ; 81 | LD BC, UART_19200 | (UART_MODE_NO_FLOW << 8) ;;; TODO This is sooooo wrong - sets C (divisor) to 38 82 | LD A, 80h ; Divisor Latch Setting Mode 83 | OUT (UART_LINE_CTRL), A ; - entered by writing 1 to bit 7 of LCR 84 | NOP 85 | NOP 86 | LD A, C 87 | OUT (UART_TX_RX), A 88 | NOP 89 | NOP 90 | XOR A 91 | OUT (UART_INT_ENABLE), A 92 | NOP 93 | NOP 94 | 95 | LD A, UART_8N1 ; Set 8N1 and exit divisor latch setting mode 96 | OUT (UART_LINE_CTRL), A 97 | 98 | LD A, 07h ; Enable and clear FIFO registers 99 | OUT (UART_FIFO_CTRL), A 100 | 101 | LD A, B 102 | AND A 103 | JR Z, _no_flowcontrol 104 | 105 | OUT (UART_MODEM_CTRL), A 106 | 107 | _no_flowcontrol NOP 108 | NOP 109 | 110 | ; 111 | ; Send 'OK' to UART 112 | ; 113 | ; 114 | LD BC, UART_TIMEOUT 115 | _check_ready1 IN A, (UART_LINE_STATUS) 116 | BIT 5, A 117 | JR NZ, _uart_ready1 ; Bit 5 is set when the UART is ready 118 | DEC BC 119 | LD A, B 120 | OR C 121 | JP NZ, _check_ready1 122 | 123 | LD HL, 07C0h ; #C1 124 | JP _boot_beep ; Beep again if we can't get ready on the UART 125 | 126 | _uart_ready1 LD A, 'O' 127 | OUT (UART_TX_RX), A 128 | 129 | 130 | LD BC, UART_TIMEOUT 131 | _check_ready2 IN A, (UART_LINE_STATUS) 132 | BIT 5, A 133 | JR NZ, _uart_ready2 ; Bit 5 is set when the UART is ready 134 | DEC BC 135 | LD A, B 136 | OR C 137 | JP NZ, _check_ready2 138 | 139 | LD HL, 07C0h ; #C1 140 | JP _boot_beep ; Beep again if we can't get ready on the UART 141 | 142 | _uart_ready2 LD A, 'K' 143 | OUT (UART_TX_RX), A 144 | 145 | 146 | LD BC, UART_TIMEOUT 147 | _check_ready3 IN A, (UART_LINE_STATUS) 148 | BIT 5, A 149 | JR NZ, _uart_ready3 ; Bit 5 is set when the UART is ready 150 | DEC BC 151 | LD A, B 152 | OR C 153 | JP NZ, _check_ready3 154 | 155 | LD HL, 07C0h ; #C1 156 | JP _boot_beep ; Beep again if we can't get ready on the UART 157 | 158 | 159 | _uart_ready3 LD A, CARRIAGE_RETURN 160 | OUT (UART_TX_RX), A 161 | 162 | 163 | LD BC, UART_TIMEOUT 164 | _check_ready4 IN A, (UART_LINE_STATUS) 165 | BIT 5, A 166 | JR NZ, _uart_ready4 ; Bit 5 is set when the UART is ready 167 | DEC BC 168 | LD A, B 169 | OR C 170 | JP NZ, _check_ready4 171 | 172 | LD HL, 07C0h ; #C1 173 | JP _boot_beep ; Beep again if we can't get ready on the UART 174 | 175 | 176 | _uart_ready4 LD A, NEWLINE 177 | OUT (UART_TX_RX), A 178 | 179 | NOP 180 | NOP 181 | 182 | LD BC, UART_TIMEOUT ; Make sure the character is sent before we re-initialise the UART later 183 | _check_ready5 IN A, (UART_LINE_STATUS) 184 | BIT 5, A 185 | JR NZ, _uart_ready5 ; Bit 5 is set when the UART is ready 186 | DEC BC 187 | LD A, B 188 | OR C 189 | JP NZ, _check_ready5 190 | 191 | _uart_ready5 192 | ; 193 | ; Now enable RAM in page 3 and test 194 | ; 195 | ; 196 | LD A, ROM_PAGE_0 197 | OUT (IO_MEM_0), A ; Page 0 is Flash 0 198 | LD A, RAM_PAGE_3 199 | OUT (IO_MEM_3), A ; Page 3 is RAM 0 200 | 201 | LD A, IO_MEM_ENABLE 202 | OUT (IO_MEM_CTRL), A 203 | 204 | LD A, 37h ; Can we write and read a value from Page 3? 205 | LD (0FF02h), A 206 | 207 | LD A, (0FF02h) 208 | LD HL, 03E0h ; #C2 209 | CP 37h 210 | 211 | JP NZ, _boot_beep ; Beep again if we don't see the value we've written 212 | INC A 213 | LD (0FF02h), A 214 | LD A, (0FF02h) 215 | CP 38h 216 | 217 | JP NZ, _boot_beep 218 | 219 | CALL uart_init ; Reinitialise the UART to make sure we've not missed anything 220 | ; 221 | ; Now check keys all read as un-pressed, apart from DELETE 222 | ; 223 | XOR A ; Reset boot mode 224 | LD (boot_mode), A 225 | 226 | LD BC, 0F700h 227 | _key_loop IN A, (C) 228 | AND 03Fh 229 | CP 03Fh 230 | JP Z, _key_ok 231 | 232 | LD L, A 233 | LD A, B 234 | CP 0EFh 235 | JP Z, _delete_row 236 | 237 | LD H,B ; If it's not the delete row, the panic code is the row and key mask 238 | JP panic 239 | 240 | _delete_row LD A, L 241 | CP 01Fh ; If it is the delete row and not the delete key, panic 0004 242 | LD HL, PANIC_0004 243 | JP NZ, panic 244 | 245 | LD A, 0FFh 246 | LD (boot_mode), A 247 | 248 | CALL uart_inline 249 | .DB "Memory test\r\n", 0 250 | 251 | CALL mem_test_start 252 | 253 | _key_ok RRC B 254 | LD A, B 255 | CP 0F7h 256 | JP NZ, _key_loop 257 | 258 | CALL uart_inline 259 | .DB "Keyboard OK\r\n", 0 260 | 261 | ; 262 | ; At this stage we should have a working UART and memory.. we can start calling routines.. 263 | ; 264 | CALL uart_inline 265 | .DB "MicroBeast starting...\n\r",0 266 | 267 | JR _continue 268 | 269 | panic CALL uart_inline 270 | .DB "Panic\n\r",0 271 | LD A, H 272 | CALL uart_hex 273 | LD A, L 274 | CALL uart_hex 275 | _beep LD DE, 0400h 276 | LD C, 5 277 | CALL play_note 278 | LD DE, 0506h 279 | LD C, 5 280 | CALL play_note 281 | JR _beep 282 | 283 | _continue CALL init_portb 284 | CALL i2c_bus_reset 285 | ; 286 | ; Now: Port B should be all inputs, so D7 (i2c data) should be high 287 | ; 288 | LD B, 0ffh 289 | DJNZ $ 290 | 291 | IN A, (PIO_B_DATA) 292 | AND I2C_DATA_MASK ; TODO - No panic code 293 | JR Z, panic 294 | 295 | CALL i2c_sda_low ; Set data low 296 | IN A, (PIO_B_DATA) 297 | AND I2C_DATA_MASK ; TODO - No panic code 298 | JR NZ, panic 299 | 300 | CALL uart_inline 301 | .DB "Detected PIO\r\n",0 302 | 303 | ; 304 | ; All good, let's see what's on the bus... 305 | ; 306 | CALL i2c_bus_reset 307 | 308 | CALL i2c_start 309 | LD A, DL_ADDRESS 310 | CALL i2c_address_w 311 | LD HL, PANIC_0001 312 | JR NC, panic 313 | CALL i2c_stop 314 | 315 | CALL uart_inline 316 | .DB "Detected Display 1/2\r\n", 0 317 | 318 | CALL i2c_start 319 | LD A, DR_ADDRESS 320 | CALL i2c_address_w 321 | LD HL, PANIC_0002 322 | JP NC, panic 323 | CALL i2c_stop 324 | 325 | CALL uart_inline 326 | .DB "Detected Display 2/2\r\n", 0 327 | 328 | CALL i2c_start 329 | LD A, RTC_ADDRESS 330 | CALL i2c_address_w 331 | LD HL, PANIC_0003 332 | JP NC, panic 333 | CALL i2c_stop 334 | 335 | CALL uart_inline 336 | .DB "Detected RTC\r\n", 0 337 | 338 | .MODULE main -------------------------------------------------------------------------------- /firmware/build.bat: -------------------------------------------------------------------------------- 1 | cd beastos 2 | tasm -t80 monitor.asm 3 | python ..\hex2inc.py monitor.obj 4 | move monitor.inc ..\build\. 5 | cd .. 6 | tasm -t80 -b firmware.asm build\firmware_p25.bin 7 | cd build 8 | globber flash.glob flash_v1.6.bin 9 | cd .. 10 | 11 | copy beastos\bios.inc build\bios_1_6.inc 12 | copy cpm\microbeast.img build\bootdisk_p25.img 13 | 14 | -------------------------------------------------------------------------------- /firmware/build/README.md: -------------------------------------------------------------------------------- 1 | # Updating Firmware 2 | 3 | To update the firmware on MicroBeast, you have two options from the Monitor: 4 | 5 | 1. Transfer the file `flash_v1.x.bin` which updates both the BIOS, CP/M AND the CP/M disk image. To transfer over 6 | the serial connection, go to `Y-Modem -> Physical Address` in the Monitor menu, and enter `25` for the page 7 | number, then `0000` for the offset (i.e. load it to RAM above the current BIOS). 8 | 9 | In your PC terminal program, send the file as normal. 10 | 11 | Once you've transferred the file, select `Write to flash` and when it asks for a page number type `00` - i.e. write the file from the start of Flash memory. 12 | 13 | 2. OR: Use the files `firmware_p25.bin` and `bootdisk_p25.img` which update the BIOS and CP/M boot disk respectively. 14 | If you are upgrading to version 1.6, you **must** upgrade both. 15 | 16 | To do this, go to `Y-Modem -> Address from file` in the Monitor menu and transfer `firmware_p25.bin` - you should 17 | then be able to choose `Update firmware` to write the new version to flash. Then repeat `Y-Modem -> Address from file` and 18 | transfer `firmware_p25.bin` - this time select `Write Flash` and enter a page number of `04` to write the boot disk 19 | to the correct location in the Flash ROM. 20 | 21 | With either option, you should get a `Done` message, and can then reboot MicroBeast 22 | 23 | Note that firmware files have a name and firmware version in the first 32 bytes or so of the file, so you 24 | can always check which version you've got by looking at the `.bin` files with a hex viewer on your PC. 25 | -------------------------------------------------------------------------------- /firmware/build/bios_1_6.inc: -------------------------------------------------------------------------------- 1 | ; 2 | ; MicroBeast BIOS.inc 3 | ; 4 | ; Include file for the MicroBeast BIOS Jump table and CP/M BIOS calls 5 | ; 6 | ; For BIOS version 1.6+ 7 | ; 8 | 9 | ; 10 | ; CP/M BDOS 2.2 call vectors. CALL BDOS with C set to one of the following values 11 | ; Reference: http://www.gaby.de/cpm/manuals/archive/cpm22htm/ch5.htm 12 | ; 13 | BDOS .EQU 00005h 14 | 15 | BDOS_RESET .EQU 00h 16 | BDOS_CONIN .EQU 01h 17 | BDOS_CONOUT .EQU 02h 18 | BDOS_READIN .EQU 03h 19 | BDOS_PUNCHOUT .EQU 04h 20 | BDOS_LISTOUT .EQU 05h 21 | BDOS_CONIO .EQU 06h 22 | BDOS_GETIOBYTE .EQU 07h 23 | BDOS_SETIOBYTE .EQU 08h 24 | BDOS_PRINTSTRING .EQU 09h 25 | BDOS_READBUFFER .EQU 0Ah 26 | BDOS_CONSOLESTATUS .EQU 0Bh 27 | BDOS_GETVERSION .EQU 0Ch 28 | BDOS_RESETDISK .EQU 0Dh 29 | BDOS_SELECTDISK .EQU 0Eh 30 | BDOS_OPENFILE .EQU 0Fh 31 | BDOS_CLOSEFILE .EQU 10h 32 | BDOS_SEARCHFIRST .EQU 11h 33 | BDOS_SEARCHNEXT .EQU 12h 34 | BDOS_DELETEFILE .EQU 13h 35 | BDOS_READSEQ .EQU 14h 36 | BDOS_WRITESEQ .EQU 15h 37 | BDOS_MAKEFILE .EQU 16h 38 | BDOS_RENAMEFILE .EQU 17h 39 | BDOS_GETLOGINVECTOR .EQU 18h 40 | BDOS_GETCURRENTDISK .EQU 19h 41 | BDOS_SETDMAADDRESS .EQU 1Ah 42 | BDOS_GETALLOCVECTOR .EQU 1Bh 43 | BDOS_WRITEPROTECT .EQU 1Ch 44 | BDOS_GETREADONLYVEC .EQU 1Dh 45 | BDOS_SETFILEATTR .EQU 1Eh 46 | BDOS_GETDISKPARAMS .EQU 1Fh 47 | BDOS_GETUSERCODE .EQU 20h 48 | BDOS_READRANDOM .EQU 21h 49 | BDOS_WRITERANDOM .EQU 22h 50 | BDOS_GETFILESIZE .EQU 23h 51 | BDOS_SETRANDOMRECORD .EQU 24h 52 | BDOS_RESETDRIVE .EQU 25h 53 | BDOS_WRITERANDOMZERO .EQU 26h 54 | 55 | 56 | ; 57 | ; Direct access to bios entrypoints - use at own risk 58 | ; 59 | BIOS_START .EQU 0EA00h ; If (WHEN) the BIOS start address changes, this will be invalidated 60 | 61 | BIOS_BOOT .EQU BIOS_START 62 | BIOS_WBOOT .EQU BIOS_START+003h 63 | BIOS_CONIST .EQU BIOS_START+006h ; Console status - Return A = 0FFH if character ready, 00H if not 64 | BIOS_CONIN .EQU BIOS_START+009h ; Console input - Wait for input, returning character in A 65 | BIOS_CONOUT .EQU BIOS_START+00Ch ; Console OUTput - Write character in C to console 66 | BIOS_LIST .EQU BIOS_START+00Fh ; List device OUTput 67 | BIOS_PUNCH_OUT .EQU BIOS_START+012h ; Punch card device OUTput 68 | BIOS_READ_IN .EQU BIOS_START+015h ; Card Reader input 69 | BIOS_DSK_HOME .EQU BIOS_START+018h ; Home disk 70 | BIOS_DSK_SELECT .EQU BIOS_START+01Bh ; Select disk 71 | BIOS_DSK_TRACK .EQU BIOS_START+01Eh ; Select track 72 | BIOS_DSK_SECTOR .EQU BIOS_START+021h ; Select sector 73 | BIOS_DSK_DMA .EQU BIOS_START+024h ; Set DMA ADDress 74 | BIOS_DSK_READ .EQU BIOS_START+027h ; Read 128 bytes 75 | BIOS_DSK_WRITE .EQU BIOS_START+02Ah ; Write 128 bytes 76 | BIOS_LIST_STATUS .EQU BIOS_START+02Dh ; List status 77 | BIOS_SECTOR_TRANSLATE .EQU BIOS_START+030h ; Sector translate 78 | 79 | 80 | ; 81 | ; MicroBeast BIOS Specific routines. These are placed at the end of the BIOS and should(!) be fixed for direct calls. 82 | ; 83 | ; 84 | 85 | 86 | ; 87 | ; CALL MBB_GET_VERSION - Get the current BIOS version 88 | ; Returns: A = Major, minor version in upper, lower nibble. e.g. 016h = version 1.6 89 | ; 90 | MBB_GET_VERSION .EQU 0FDFAh 91 | 92 | ; 93 | ; CALL MBB_PLAY_NOTE - Play a note on the speaker 94 | ; Parameters: 95 | ; D = Octave 2-6 96 | ; E = Note 0-11 97 | ; C = 1-15 duration, ~tenths of a second 98 | ; 99 | MBB_PLAY_NOTE .EQU 0FDF7h 100 | 101 | ; 102 | ; CALL MBB_WAIT_KEY - Waits for until a key is pressed and released 103 | ; 104 | MBB_WAIT_KEY .EQU 0FDF4h 105 | 106 | ; 107 | ; CALL MBB_I2C_RD_ADDRESS - Read a byte from device, with address. i2c_stop is not called. 108 | ; Parameters: 109 | ; H = Device ID 110 | ; L = Address 111 | ; Returns: 112 | ; A = Byte read 113 | ; Carry SET if success. 114 | ; 115 | MBB_I2C_RD_ADDRESS .EQU 0FDF1h 116 | 117 | ; 118 | ; CALL MBB_I2C_WR_ADDRESS - Start writing to a device, with address. i2c_stop is not called. 119 | ; Parameters: 120 | ; H = Device ID 121 | ; L = Address 122 | ; Returns: 123 | ; Carry SET if success. 124 | ; 125 | MBB_I2C_WR_ADDRESS .EQU 0FDEEh 126 | 127 | ; 128 | ; CALL MBB_I2C_READ - Read a byte from current device, without ACK. 129 | ; Returns: 130 | ; A = Byte read 131 | ; 132 | MBB_I2C_READ .EQU 0FDEBh 133 | 134 | ; 135 | ; CALL MBB_I2C_WRITE - Write a byte to current device. i2c_stop is not called. 136 | ; Parameters: 137 | ; A = Byte to write 138 | ; Returns: 139 | ; Carry SET if success. 140 | ; 141 | MBB_I2C_WRITE .EQU 0FDE8h 142 | 143 | ; 144 | ; CALL MBB_I2C_STOP - Send I2C Stop sequence 145 | ; 146 | MBB_I2C_STOP .EQU 0FDE5h 147 | 148 | ; 149 | ; CALL MBB_I2C_START - Send I2C Start sequence 150 | ; 151 | MBB_I2C_START .EQU 0FDE2h 152 | 153 | ; 154 | ; CALL MBB_SET_PAGE - Set page mapping 155 | ; Parameters: 156 | ; A = Logical (CPU) page to set (0-2) 157 | ; E = Physical page (00-1F: ROM 20-3F: RAM) 158 | ; 159 | MBB_SET_PAGE .EQU 0FDDFh 160 | 161 | ; 162 | ; CALL MBB_GET_PAGE - Get page mapping 163 | ; Parameters: 164 | ; C = Logical (CPU) page to get (0-2) 165 | ; Returns 166 | ; A = Physical page (00-1F: ROM 20-3F: RAM), or 0FFH for error 167 | ; 168 | MBB_GET_PAGE .EQU 0FDDCh 169 | 170 | ; 171 | ; CALL MBB_PRINT - Print following inline text, zero terminated 172 | ; .DB "Test to print", 0 173 | ; 174 | MBB_PRINT .EQU 0FDD9h 175 | 176 | ; 177 | ; CALL MBB_WRITE_LED - Directly write bitmask to LED display (Check Font editor online for bit order) 178 | ; Parameters: 179 | ; HL = Bit pattern to write to LED digit 180 | ; A = Column (0-23) 181 | ; 182 | MBB_WRITE_LED .EQU 0FDD6h 183 | 184 | ; 185 | ; CALL MBB_LED_BRIGHTNESS - Set segments in digit A to brightness C 186 | ; Parameters: 187 | ; A = Column (0-23) 188 | ; C = Brightness (0-128) 189 | ; 190 | MBB_LED_BRIGHTNESS .EQU 0FDD3h 191 | 192 | ; 193 | ; CALL MBB_RTC_TIME - Get the current time from the RTC 194 | ; Parameters: 195 | ; HL = Address of 7 byte time data block to store current time 196 | ; Returns: 197 | ; Carry SET if success 198 | ; 199 | ; Time Data block 200 | ; HL -> Seconds - 2 digits BCD 201 | ; HL+1 -> Minutes - 2 digits BCD 202 | ; HL+2 -> Hour - 24hr clock, 2 digits BCD 203 | ; HL+3 -> Weekday (1-7. Monday=1) 204 | ; HL+4 -> Day 1-31, 2 digits BCD 205 | ; HL+5 -> Month 1-12, 2 digits BCD 206 | ; HL+6 -> Year, 2 digits BCD 207 | ; 208 | MBB_RTC_TIME .EQU 0FDD0h 209 | 210 | ; CALL MBB_GET_DRIVE_PAGE - Get the page in memory being used as the base for the drive selected by A 211 | ; Parameters: 212 | ; A = Drive number 0, 1 213 | ; Returns: 214 | ; A = Page in ROM/RAM for the given drive 215 | ; or A = 0 if the selected drive is not supported. 216 | ; 217 | MBB_GET_DRIVE_PAGE .EQU 0FDCDh 218 | 219 | ; CALL MBB_FLASH_WRITE - Erase and write flash data. Data is written to 4K sectors, which are erased 220 | ; before writing. This uses Page 0 to write the data, so the source must be above 3FFFh 221 | ; Data is written from the start of the specified 4K sector 222 | ; Note: This means if BC is an exact multiple of sector size, D is returned as the previous sector 223 | ; 224 | ; Parameters: 225 | ; D -> 7 bit index of 4K sector being written 226 | ; HL -> Address of source data 227 | ; BC -> bytes to write 228 | ; Returns: 229 | ; D pointing to last sector written 230 | ; 231 | MBB_FLASH_WRITE .EQU 0FDCAh 232 | 233 | ; CALL MBB_SET_USR_INT - Set or query the user interrupt. 234 | ; The specified routine will be called after keyboard polling, every 60th of a second. The shadow register 235 | ; set is selected before the call (EXX), and AF is preserved. The routine should RETurn normally. 236 | ; Interrupt routines survive warm reboots, but no special measures are taken to ensure the memory they 237 | ; occupy is preserved. 238 | ; 239 | ; Parameters: 240 | ; HL = Address of user interrupt routine, or zero to disable. Call with 0FFFFh to query the current value 241 | ; Returns: 242 | ; The address of the current user interrupt routine, or zero if none is configured. 243 | ; 244 | MBB_SET_USR_INT .EQU 0FDC7h 245 | 246 | -------------------------------------------------------------------------------- /firmware/build/bootdisk_p25.img: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atoone/MicroBeast/4c5a9fdd1e71aa5e0d928267e6e1ae4ae0d5ae87/firmware/build/bootdisk_p25.img -------------------------------------------------------------------------------- /firmware/build/firmware_p24.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atoone/MicroBeast/4c5a9fdd1e71aa5e0d928267e6e1ae4ae0d5ae87/firmware/build/firmware_p24.bin -------------------------------------------------------------------------------- /firmware/build/firmware_p25.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atoone/MicroBeast/4c5a9fdd1e71aa5e0d928267e6e1ae4ae0d5ae87/firmware/build/firmware_p25.bin -------------------------------------------------------------------------------- /firmware/build/flash.glob: -------------------------------------------------------------------------------- 1 | # Globber script for Flash image 2 | # 3 | append file firmware_p25.bin exactly 64k pad 0 4 | append file ../cpm/microbeast.img 5 | -------------------------------------------------------------------------------- /firmware/build/flash_v1.3.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atoone/MicroBeast/4c5a9fdd1e71aa5e0d928267e6e1ae4ae0d5ae87/firmware/build/flash_v1.3.bin -------------------------------------------------------------------------------- /firmware/build/flash_v1.4.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atoone/MicroBeast/4c5a9fdd1e71aa5e0d928267e6e1ae4ae0d5ae87/firmware/build/flash_v1.4.bin -------------------------------------------------------------------------------- /firmware/build/flash_v1.6.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atoone/MicroBeast/4c5a9fdd1e71aa5e0d928267e6e1ae4ae0d5ae87/firmware/build/flash_v1.6.bin -------------------------------------------------------------------------------- /firmware/cpm/blank_disk.img: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atoone/MicroBeast/4c5a9fdd1e71aa5e0d928267e6e1ae4ae0d5ae87/firmware/cpm/blank_disk.img -------------------------------------------------------------------------------- /firmware/cpm/cpm22.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atoone/MicroBeast/4c5a9fdd1e71aa5e0d928267e6e1ae4ae0d5ae87/firmware/cpm/cpm22.bin -------------------------------------------------------------------------------- /firmware/cpm/microbeast.img: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atoone/MicroBeast/4c5a9fdd1e71aa5e0d928267e6e1ae4ae0d5ae87/firmware/cpm/microbeast.img -------------------------------------------------------------------------------- /firmware/disp.asm: -------------------------------------------------------------------------------- 1 | ; ========================================== Display Routines =============================================== 2 | ; 3 | ; Copyright (c) 2023 Andy Toone for Feersum Technology Ltd. 4 | ; 5 | ; Part of the MicroBeast Z80 kit computer project. Support hobby electronics. 6 | ; 7 | ; Permission is hereby granted, free of charge, to any person obtaining a copy 8 | ; of this software and associated documentation files (the "Software"), to deal 9 | ; in the Software without restriction, including without limitation the rights 10 | ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | ; copies of the Software, and to permit persons to whom the Software is 12 | ; furnished to do so, subject to the following conditions: 13 | ; 14 | ; The above copyright notice and this permission notice shall be included in all 15 | ; copies or substantial portions of the Software. 16 | ; 17 | ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | ; SOFTWARE. 24 | ; 25 | .MODULE disp 26 | 27 | CONFIG_PAGE .EQU 3 28 | BRIGHT_PAGE .EQU 1 29 | LED_PAGE .EQU 0 30 | 31 | display_init CALL disp_clear 32 | LD E, DISP_DEFAULT_BRIGHTNESS 33 | CALL disp_brightness 34 | 35 | CALL disp_select_l 36 | CALL disp_config 37 | 38 | CALL disp_select_r 39 | CALL disp_config 40 | 41 | disp_select_l LD A, DL_ADDRESS 42 | LD (display_address), A 43 | RET 44 | 45 | disp_select_r LD A, DR_ADDRESS 46 | LD (display_address), A 47 | RET 48 | 49 | disp_config LD L, CONFIG_PAGE 50 | CALL disp_page 51 | CALL i2c_start 52 | LD A, (display_address) 53 | CALL i2c_address_w 54 | LD A, 000h 55 | CALL i2c_write 56 | LD A, 001h ; Turn display on 57 | CALL i2c_write 58 | LD A, 078h ; 0.020mA 59 | CALL i2c_write 60 | JP i2c_stop 61 | 62 | ; 63 | ; Sets the brightness for the display 64 | ; Enter with E set to the desired brightness for all segments 65 | ; 66 | disp_brightness CALL disp_select_l 67 | CALL _set_bright 68 | CALL disp_select_r 69 | _set_bright LD L, BRIGHT_PAGE 70 | CALL disp_page 71 | LD L, 12 72 | _bright_loop CALL i2c_start 73 | LD A, (display_address) 74 | CALL i2c_address_w 75 | LD A, L 76 | DEC A 77 | SLA A 78 | SLA A 79 | SLA A 80 | SLA A 81 | CALL i2c_write 82 | LD H, 010h 83 | _bright_byte LD A, E 84 | CALL i2c_write 85 | DEC H 86 | JR NZ, _bright_byte 87 | CALL i2c_stop 88 | DEC L 89 | JR NZ, _bright_loop 90 | LD L, LED_PAGE 91 | CALL disp_page 92 | RET 93 | 94 | ; Set the Page number 95 | ; Call with page number in L 96 | ; 97 | ; Uses A, B, C, D 98 | disp_page CALL disp_unlock 99 | CALL i2c_start 100 | LD A, (display_address) 101 | CALL i2c_address_w 102 | LD A, 0FDh 103 | CALL i2c_write 104 | LD A, L 105 | CALL i2c_write 106 | JP i2c_stop 107 | 108 | disp_unlock CALL i2c_start ; Must be called before switching pages 109 | LD A, (display_address) 110 | CALL i2c_address_w 111 | LD A, DISP_REG_CRWL 112 | CALL i2c_write 113 | LD A, DISP_UNLOCK 114 | CALL i2c_write 115 | JP i2c_stop 116 | 117 | ; Set the character at column A to brightness C 118 | ; 119 | ; 120 | disp_char_bright PUSH BC 121 | LD B, DL_ADDRESS 122 | CP 12 123 | JP C, _bright_left 124 | LD B, DR_ADDRESS 125 | SUB 12 126 | _bright_left LD E, A 127 | LD A, B 128 | LD (display_address), A 129 | LD L, BRIGHT_PAGE 130 | CALL disp_page 131 | 132 | CALL i2c_start 133 | LD A, (display_address) 134 | CALL i2c_address_w 135 | LD A, E 136 | SLA A 137 | SLA A 138 | SLA A 139 | SLA A 140 | CALL i2c_write 141 | POP HL 142 | LD H, 010h 143 | _bright_char_loop LD A, L 144 | CALL i2c_write 145 | DEC H 146 | JR NZ, _bright_char_loop 147 | CALL i2c_stop 148 | 149 | LD L, LED_PAGE 150 | CALL disp_page 151 | RET 152 | 153 | ; Display a single character A at column C 154 | ; 155 | ; Returns with A pointing to next column 156 | ; 157 | disp_character CP 32 158 | JP P, _not_control 159 | 160 | _invalid_char LD HL, INVALID_CHAR_BITMASK 161 | LD A, C 162 | JP disp_bitmask 163 | 164 | _not_control BIT 7, A 165 | JP NZ, _invalid_char 166 | SUB 32 167 | 168 | LD D, 0 169 | LD E, A 170 | SLA E ; Don't need to shift into D, since bit 7 is zero 171 | LD HL, font 172 | ADD HL, DE 173 | LD D, (HL) 174 | INC HL 175 | LD H, (HL) 176 | LD L, D 177 | LD A, C 178 | ; Fall into disp_bitmask 179 | 180 | ; Display a bitmask in HL at column A (0 - 23) 181 | ; 182 | ; Returns with A pointing to next column 183 | ; 184 | ; Uses A, B, C, D, E 185 | disp_bitmask PUSH AF 186 | LD B, DL_ADDRESS 187 | CP 12 188 | JP C, _disp_left 189 | LD B, DR_ADDRESS 190 | SUB 12 191 | _disp_left LD E, A 192 | CALL i2c_start 193 | LD A, B 194 | CALL i2c_address_w 195 | LD A, E 196 | SLA A 197 | CALL i2c_write 198 | LD A, L 199 | CALL i2c_write 200 | LD A, H 201 | CALL i2c_write 202 | CALL i2c_stop 203 | POP AF 204 | INC A 205 | RET 206 | 207 | ; 208 | ; Clear the display and show an inline string from column 0 209 | ; 210 | disp_clear_inline CALL disp_clear 211 | XOR A 212 | ; 213 | ; Display an inline string to column A-> 214 | ; 215 | disp_inline EX (SP), HL 216 | CALL disp_string 217 | INC HL 218 | EX (SP), HL 219 | RET 220 | 221 | ; Display a string pointed to by HL to column A-> 222 | ; Note string should be zero terminated... 223 | ; Returns with HL pointing to the 0 terminator 224 | ; 225 | disp_string LD C, A 226 | LD A, (HL) 227 | OR A 228 | JP NZ, _char_ok 229 | RET 230 | 231 | _char_ok PUSH HL 232 | CALL disp_character 233 | POP HL 234 | INC HL 235 | JR disp_string 236 | 237 | ; Clear the display 238 | ; 239 | disp_clear LD A, 0 240 | LD HL, 0 241 | _clear_loop CALL disp_bitmask 242 | CP 24 243 | JP NZ, _clear_loop 244 | RET 245 | 246 | .MODULE main -------------------------------------------------------------------------------- /firmware/firmware.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; MicroBeast Firmware - boot MicroBeast and launch embedded monitor, bios and other systems 3 | ; 4 | ; 5 | ; Copyright (c) 2023 Andy Toone for Feersum Technology Ltd. 6 | ; 7 | ; Part of the MicroBeast Z80 kit computer project. Support hobby electronics. 8 | ; 9 | ; Permission is hereby granted, free of charge, to any person obtaining a copy 10 | ; of this software and associated documentation files (the "Software"), to deal 11 | ; in the Software without restriction, including without limitation the rights 12 | ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | ; copies of the Software, and to permit persons to whom the Software is 14 | ; furnished to do so, subject to the following conditions: 15 | ; 16 | ; The above copyright notice and this permission notice shall be included in all 17 | ; copies or substantial portions of the Software. 18 | ; 19 | ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | ; SOFTWARE. 26 | ; 27 | .MODULE main 28 | .INCLUDE "ports.asm" 29 | .INCLUDE "shared_data.asm" 30 | 31 | 32 | .org 0h 33 | DI ; Disable Z80 interrupts 34 | JR _start 35 | 36 | .DB "Firmware 1.6 11/05/25",0,0 37 | 38 | _start LD SP, 0h ; Set SP 39 | 40 | .INCLUDE "boot_seq.asm" 41 | 42 | _main CALL init_portb 43 | CALL i2c_bus_reset 44 | 45 | CALL display_init 46 | 47 | LD E, 0 ; Set brightness to zero 48 | CALL disp_brightness 49 | 50 | LD A, 0 51 | LD HL, welcome 52 | CALL disp_string 53 | 54 | ;; Animate it 55 | LD A, DL_ADDRESS ; Put both controllers in brightness mode 56 | LD (display_address), A 57 | LD L, BRIGHT_PAGE 58 | CALL disp_page 59 | 60 | LD A, DR_ADDRESS 61 | LD (display_address), A 62 | LD L, BRIGHT_PAGE 63 | CALL disp_page 64 | 65 | LD A, 0 ; Current animation from 0-24 66 | LD (temp_byte), A 67 | 68 | ; Update display 69 | _frame_loop CALL i2c_start 70 | LD A, DL_ADDRESS 71 | CALL i2c_address_w 72 | XOR A ; First digit in display 73 | CALL i2c_write 74 | 75 | LD B, 12 76 | LD A, (temp_byte) 77 | LD C, A 78 | 79 | _l_char_loop PUSH BC 80 | LD B, 0 81 | LD HL, little_sin 82 | ADD HL, BC 83 | 84 | LD E, 16 85 | _write_l_char LD A, (HL) 86 | CALL i2c_write 87 | DEC E 88 | JR NZ, _write_l_char 89 | 90 | POP BC 91 | INC C 92 | INC C 93 | LD A, C 94 | CP 24 95 | JR C, _no_loop_l 96 | SBC A, 24 97 | LD C, A 98 | _no_loop_l DJNZ _l_char_loop 99 | CALL i2c_stop 100 | 101 | PUSH BC 102 | CALL i2c_start 103 | LD A, DR_ADDRESS 104 | CALL i2c_address_w 105 | XOR A 106 | CALL i2c_write 107 | 108 | POP BC 109 | LD B, 12 110 | 111 | _r_char_loop PUSH BC 112 | LD B, 0 113 | LD HL, little_sin 114 | ADD HL, BC 115 | 116 | LD E, 16 117 | _write_r_char LD A, (HL) 118 | CALL i2c_write 119 | DEC E 120 | JR NZ, _write_r_char 121 | 122 | POP BC 123 | INC C 124 | INC C 125 | LD A, C 126 | CP 24 127 | JR C, _no_loop_r 128 | SBC A, 24 129 | LD C, A 130 | _no_loop_r DJNZ _r_char_loop 131 | CALL i2c_stop 132 | 133 | _next_frame LD A, (temp_byte) 134 | INC A 135 | LD (temp_byte), A 136 | CP 24 137 | JP NZ, _frame_loop 138 | 139 | LD E, DISP_DEFAULT_BRIGHTNESS ; Reset brightness 140 | CALL disp_brightness 141 | 142 | LD A, 0 143 | LD HL, welcome2 144 | CALL disp_string 145 | 146 | CALL wait_key 147 | 148 | ;======================================== SETUP BIOS ======================================== 149 | 150 | LD HL, bios_seg+4 151 | LD DE, (bios_seg) 152 | PUSH DE 153 | LD BC, (bios_seg+2) 154 | LDIR 155 | RET 156 | 157 | little_sin .DB 0, 3, 9, 19, 32, 48, 64, 81, 96, 110, 120, 126, 128, 126, 120, 110, 96, 81, 65, 48, 33, 19, 9, 3 ; 24 values 158 | 159 | halt JR halt 160 | 161 | wait_key LD BC, 0000h ; Keyboard all rows 162 | _wait_key IN A, (C) 163 | AND 3fh 164 | CP 3fh 165 | JP Z, _wait_key 166 | 167 | _wait_up LD D, 100 168 | _wait_loop IN A, (C) 169 | AND 3fh 170 | CP 3fh 171 | JP NZ, _wait_up 172 | DEC D 173 | JP NZ, _wait_loop 174 | RET 175 | 176 | welcome .db "************************", 0 177 | welcome2 .db "* MICRO BEAST Ver 1_6 *", 0 178 | 179 | ; 180 | ; Write A as a hex byte 181 | ; Overwrites A... 182 | ; 183 | uart_hex PUSH AF 184 | SRA A 185 | SRA A 186 | SRA A 187 | SRA A 188 | CALL to_hex 189 | CALL uart_send 190 | POP AF 191 | CALL to_hex 192 | JP uart_send 193 | ; 194 | ; Returns the low nibble of A as a hex digit 195 | ; 196 | to_hex AND $0F ;LOW NIBBLE ONLY 197 | ADD A,$90 198 | DAA 199 | ADC A,$40 200 | DAA 201 | RET 202 | ; 203 | ; Inline send. Sends the zero terminated string immediately following the call to this function to the UART. 204 | ; e.g. CALL uart_inline 205 | ; .DB "My text to send", 0 206 | ; 207 | ; Returns with Carry set if the string was successfully sent, otherwise, carry is clear. 208 | ; 209 | ; Uses A 210 | ; 211 | uart_inline EX (SP), HL 212 | CALL uart_string 213 | JP C, _inline_end 214 | _find_end LD A, (HL) ; Get the current character (Carry preserved) 215 | INC HL ; Point to next character (Carry preserved) 216 | AND A ; Test if the current character was zero (Clears carry) 217 | JP NZ, _find_end ; If it was, we're done, otherwise repeat 218 | _inline_end EX (SP), HL 219 | RET 220 | ; 221 | ; Send a zero terminated string pointed to by HL to the UART 222 | ; 223 | ; Returns with Carry Set if the string was sent sucessfully, clear otherwise 224 | ; 225 | uart_string LD A,(HL) 226 | INC HL 227 | AND A 228 | JP Z, _string_end 229 | CALL uart_send 230 | JP C, uart_string 231 | RET 232 | _string_end SCF 233 | RET 234 | 235 | ; =============================================== Font ===================================================== 236 | ; 237 | .INCLUDE disp.asm 238 | .INCLUDE font.asm 239 | .INCLUDE i2c.asm 240 | .INCLUDE io.asm 241 | .INCLUDE uart.asm 242 | .include memory_test.asm 243 | 244 | bios_seg .INCLUDE build/monitor.inc 245 | .END 246 | -------------------------------------------------------------------------------- /firmware/flash.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; Flash update routines 3 | ; 4 | ; Note that any memory write operations *at all* during flash updates will cancel the current operation. 5 | ; That means no data can be stored to memory, no stack operations (call, push), no interrupts. 6 | ; 7 | ; 8 | ; Copyright (c) 2023 Andy Toone for Feersum Technology Ltd. 9 | ; 10 | ; Part of the MicroBeast Z80 kit computer project. Support hobby electronics. 11 | ; 12 | ; Permission is hereby granted, free of charge, to any person obtaining a copy 13 | ; of this software and associated documentation files (the "Software"), to deal 14 | ; in the Software without restriction, including without limitation the rights 15 | ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | ; copies of the Software, and to permit persons to whom the Software is 17 | ; furnished to do so, subject to the following conditions: 18 | ; 19 | ; The above copyright notice and this permission notice shall be included in all 20 | ; copies or substantial portions of the Software. 21 | ; 22 | ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | ; SOFTWARE. 29 | ; 30 | .MODULE flash 31 | 32 | _cmd_1_addr .EQU 05555h 33 | _cmd_2_addr .EQU 02AAAh 34 | 35 | _bank_mask .EQU 03FFFh ; One memory bank is 14 bits -> 16Kb 36 | _sector_mask .EQU 00FFFh ; A sector is 12 bits -> 4Kb 37 | 38 | _cmd_1_addr_bank .EQU _cmd_1_addr >> 14 39 | _cmd_2_addr_bank .EQU _cmd_2_addr >> 14 40 | _cmd_3_addr_bank .EQU _cmd_1_addr_bank 41 | _cmd_4_addr_bank .EQU _cmd_1_addr_bank 42 | _cmd_5_addr_bank .EQU _cmd_2_addr_bank 43 | 44 | _cmd_1_logical_addr .EQU _cmd_1_addr & _bank_mask 45 | _cmd_2_logical_addr .EQU _cmd_2_addr & _bank_mask 46 | _cmd_3_logical_addr .EQU _cmd_1_logical_addr 47 | _cmd_4_logical_addr .EQU _cmd_1_logical_addr 48 | _cmd_5_logical_addr .EQU _cmd_2_logical_addr 49 | 50 | _cmd_1_data .EQU 0AAh 51 | _cmd_2_data .EQU 055h 52 | _cmd_3_data_write .EQU 0A0h 53 | _cmd_3_data_erase .EQU 080h 54 | _cmd_4_data .EQU 0AAh 55 | _cmd_5_data .EQU 055h 56 | 57 | _cmd_6_data_erase .EQU 030h 58 | 59 | ; 60 | ; Enter with A -> 7 bit index of 4K sector to be erased. 61 | ; 62 | ; Preserves BC, DE, HL 63 | ; 64 | ; Note this uses bank 0, and leaves it configured for the page containing the erased sector 65 | ; 66 | ; Typical time to erase sector ~18ms 67 | ; 68 | flash_sector_erase DI ; Disable interrupts 69 | PUSH HL 70 | PUSH BC 71 | PUSH DE 72 | 73 | AND 07fh 74 | LD D, A 75 | SRL D 76 | SRL D ; D is now the bank number 77 | 78 | SLA A 79 | SLA A 80 | SLA A 81 | SLA A 82 | AND 030h 83 | LD E, A ; E is the sector within the bank shifted into bits 13 & 12 84 | 85 | LD C, IO_MEM_0 ; Use bank 0 to write to 86 | LD A, _cmd_1_addr_bank 87 | OUT (C), A 88 | LD HL, _cmd_1_logical_addr 89 | LD (HL), _cmd_1_data 90 | 91 | LD A, _cmd_2_addr_bank 92 | OUT (C), A 93 | LD HL, _cmd_2_logical_addr 94 | LD (HL), _cmd_2_data 95 | 96 | LD A, _cmd_3_addr_bank 97 | OUT (C), A 98 | LD HL, _cmd_3_logical_addr 99 | LD (HL), _cmd_3_data_erase 100 | 101 | LD A, _cmd_4_addr_bank 102 | OUT (C), A 103 | LD HL, _cmd_4_logical_addr 104 | LD (HL), _cmd_4_data 105 | 106 | LD A, _cmd_5_addr_bank 107 | OUT (C), A 108 | LD HL, _cmd_5_logical_addr 109 | LD (HL), _cmd_5_data 110 | 111 | OUT (C), D ; Switch to the bank containing our sector 112 | LD H, E ; And write the sector bits as an address (bits 0-11 are ignored) 113 | LD (HL), _cmd_6_data_erase 114 | 115 | _wait_erase LD A,(HL) 116 | RLC A 117 | JR NC, _wait_erase 118 | 119 | POP DE 120 | POP BC 121 | POP HL 122 | EI 123 | RET 124 | 125 | ; 126 | ; Enter with A -> Byte to write 127 | ; D -> 7 bit index of 4K sector being written 128 | ; HL -> 12 bit address of byte within sector 129 | ; 130 | ; Preserves D, HL 131 | ; Uses A, BC, E 132 | ; 133 | ; Typical time to erase byte ~14us 134 | ; 135 | flash_write_byte DI 136 | LD E, A ; Preserve our byte 137 | 138 | LD A, H ; Make sure HL is within our sector 139 | AND _sector_mask >> 8 140 | LD H, A 141 | 142 | LD A, D ; Make sure D is a valid sector index 143 | AND 07fh 144 | LD D, A 145 | LD B, A 146 | 147 | LD A, D ; Get the bottom 2 bits of our sector index.. 148 | AND 03h 149 | SLA A 150 | SLA A 151 | SLA A 152 | SLA A 153 | OR H 154 | LD H, A ; ..and OR them into H to get a 14 bit address within our bank 155 | 156 | SRL D 157 | SRL D ; D is now our bank number 158 | 159 | PUSH HL 160 | 161 | LD C, IO_MEM_0 ; Use bank 0 to write to 162 | LD A, _cmd_1_addr_bank 163 | OUT (C), A 164 | LD HL, _cmd_1_logical_addr 165 | LD (HL), _cmd_1_data 166 | 167 | LD A, _cmd_2_addr_bank 168 | OUT (C), A 169 | LD HL, _cmd_2_logical_addr 170 | LD (HL), _cmd_2_data 171 | 172 | LD A, _cmd_3_addr_bank 173 | OUT (C), A 174 | LD HL, _cmd_3_logical_addr 175 | LD (HL), _cmd_3_data_write 176 | 177 | OUT (C), D 178 | POP HL 179 | LD (HL), E 180 | 181 | _wait_byte LD A, (HL) 182 | XOR E 183 | RLC A 184 | JR NC, _wait_byte 185 | 186 | LD A, H ; Clear bits 13 & 12 to restore HL to sector address.. 187 | AND _sector_mask >> 8 188 | LD H, A 189 | 190 | LD D, B ; And restore D 191 | EI 192 | RET 193 | 194 | ; 195 | ; Write a flash data block. This uses Page 0 to write the data, so the source must be above 3FFFh 196 | ; 197 | ; D -> 7 bit index of 4K sector being written 198 | ; HL -> Address of source data 199 | ; BC -> bytes to write 200 | ; 201 | ; Returns D pointing to last sector written 202 | ; Note: This means if BC is an exact multiple of sector size, D is returned as the previous sector 203 | 204 | flash_write PUSH IX 205 | PUSH HL 206 | POP IX 207 | LD HL, 0 ; Address in sector.. 208 | 209 | _erase_sector ; Lower 12 bits of HL are zero, erase sector before writing bytes 210 | LD A, D 211 | CALL flash_sector_erase 212 | _write_loop LD A, (IX+0) 213 | PUSH BC 214 | CALL flash_write_byte 215 | POP BC 216 | 217 | INC IX 218 | DEC BC 219 | LD A, B 220 | OR C 221 | JR Z, _success 222 | 223 | INC HL 224 | LD A, L 225 | AND A 226 | JR NZ, _write_loop 227 | LD A, H 228 | AND _sector_mask >> 8 229 | LD H, A 230 | JR NZ, _write_loop 231 | 232 | INC D 233 | JR _erase_sector 234 | 235 | _success POP IX 236 | RET 237 | 238 | .MODULE main 239 | -------------------------------------------------------------------------------- /firmware/font.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; Font definition 3 | ; 4 | ; 5 | ; Copyright (c) 2023 Andy Toone for Feersum Technology Ltd. 6 | ; 7 | ; Part of the MicroBeast Z80 kit computer project. Support hobby electronics. 8 | ; 9 | ; Permission is hereby granted, free of charge, to any person obtaining a copy 10 | ; of this software and associated documentation files (the "Software"), to deal 11 | ; in the Software without restriction, including without limitation the rights 12 | ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | ; copies of the Software, and to permit persons to whom the Software is 14 | ; furnished to do so, subject to the following conditions: 15 | ; 16 | ; The above copyright notice and this permission notice shall be included in all 17 | ; copies or substantial portions of the Software. 18 | ; 19 | ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | ; SOFTWARE. 26 | ; 27 | 28 | INVALID_CHAR_BITMASK .EQU 04861h 29 | 30 | font 31 | .dw 0000h 32 | .dw 4900h ; ! 33 | .dw 0202h ; " 34 | .dw 12ceh ; # 35 | .dw 12edh ; $ 36 | .dw 2de4h ; % 37 | .dw 0b59h ; & 38 | .dw 0200h ; ' 39 | .dw 0c00h ; ( 40 | .dw 2100h ; ) 41 | .dw 3fc0h ; * 42 | .dw 12c0h ; + 43 | .dw 2000h ; , 44 | .dw 00c0h ; - 45 | .dw 4000h ; . 46 | .dw 2400h ; / 47 | 48 | .dw 243fh ; 0 49 | .dw 0406h ; 1 50 | .dw 00dbh ; 2 51 | .dw 008fh ; 3 52 | .dw 00e6h ; 4 53 | .dw 0869h ; 5 54 | .dw 00fdh ; 6 55 | .dw 1401h ; 7 56 | .dw 00ffh ; 8 57 | .dw 00efh ; 9 58 | .dw 0040h ; : 59 | .dw 2200h ; ; 60 | .dw 0c40h ; < 61 | .dw 00c8h ; = 62 | .dw 2180h ; > 63 | .dw 5083h ; ? 64 | 65 | .dw 02bbh ; @ 66 | .dw 00f7h ; A 67 | .dw 128fh ; B 68 | .dw 0039h ; C 69 | .dw 120fh ; D 70 | .dw 0079h ; E 71 | .dw 0071h ; F 72 | .dw 00bdh ; G 73 | .dw 00f6h ; H 74 | .dw 1209h ; I 75 | .dw 001eh ; J 76 | .dw 0c70h ; K 77 | .dw 0038h ; L 78 | .dw 0536h ; M 79 | .dw 0936h ; N 80 | .dw 003fh ; O 81 | 82 | .dw 00f3h ; P 83 | .dw 083fh ; Q 84 | .dw 08f3h ; R 85 | .dw 00edh ; S 86 | .dw 1201h ; T 87 | .dw 003eh ; U 88 | .dw 2430h ; V 89 | .dw 2836h ; W 90 | .dw 2d00h ; X 91 | .dw 00eeh ; Y 92 | .dw 2409h ; Z 93 | .dw 0039h ; [ 94 | .dw 0900h ; \ 95 | .dw 000fh ; ] 96 | .dw 2800h ; ^ 97 | .dw 0008h ; _ 98 | 99 | .dw 0100h ; ` 100 | .dw 208ch ; a 101 | .dw 0878h ; b 102 | .dw 00d8h ; c 103 | .dw 208eh ; d 104 | .dw 2058h ; e 105 | .dw 14c0h ; f 106 | .dw 048eh ; g 107 | .dw 1070h ; h 108 | .dw 1000h ; i 109 | .dw 2210h ; j 110 | .dw 1e00h ; k 111 | .dw 1200h ; l 112 | .dw 10d4h ; m 113 | .dw 1050h ; n 114 | .dw 00dch ; o 115 | 116 | .dw 0170h ; p 117 | .dw 0486h ; q 118 | .dw 0050h ; r 119 | .dw 0888h ; s 120 | .dw 0078h ; t 121 | .dw 001ch ; u 122 | .dw 2010h ; v 123 | .dw 2814h ; w 124 | .dw 2d00h ; x 125 | .dw 028eh ; y 126 | .dw 2048h ; z 127 | .dw 2149h ; { 128 | .dw 1200h ; | 129 | .dw 0c89h ; } 130 | .dw 24c0h ; ~ 131 | .dw 0000h ; -------------------------------------------------------------------------------- /firmware/hex2inc.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | if len(sys.argv) < 2: 4 | print("hex2inc - convert IBM Hex data file to Assembler Include file") 5 | print("Useage: hex2inc input-file [output-file]") 6 | quit() 7 | 8 | 9 | # Using readlines() 10 | filename = sys.argv[1] 11 | if filename.find(".") < 0: 12 | filename += ".obj" 13 | 14 | name = filename.split(".")[0] 15 | outfile = name+".inc" 16 | 17 | if len(sys.argv) > 2: 18 | outfile = sys.argv[2] 19 | 20 | if outfile.find(".") < 0: 21 | outfile += ".inc" 22 | 23 | print("Parsing {} -> {}".format(filename, outfile)) 24 | 25 | file1 = open(filename, 'r') 26 | Lines = file1.readlines() 27 | 28 | startAddress = -1 29 | endAddress = -1 30 | 31 | count = 0 32 | # Format is :[HH: Byte count][HHHH: Address][HH: Record type]{HH...: Data}[HH: Checksum] 33 | # Strips the newline character 34 | 35 | output = [] 36 | 37 | output.append("; Autogenerated by hex2inc from {}\n;\n".format(filename)) 38 | 39 | for line in Lines: 40 | count += 1 41 | line = line.strip() 42 | if line.startswith(":") and len(line) > 10: 43 | checksum = 0 44 | for index in range(1, len(line)-2, 2): 45 | # print( "{} -> {}".format(index, line[index: index+2]) ) 46 | byte = int( line[index: index+2], 16) 47 | checksum += byte 48 | 49 | checksum = (~(checksum & 0x0ff)+1) & 0x0FF 50 | expected = int( line[-2:], 16) 51 | if checksum != expected: 52 | raise Exception("Checksum error on line {} : {} - got {} ".format(count, line, checksum)) 53 | 54 | byteCount = int( line[1:3], 16 ) 55 | address = int( line[3:7], 16 ) 56 | recordType = int( line[7:9], 16 ) 57 | ended = False 58 | 59 | if recordType == 0x00: #Data 60 | if startAddress < 0: 61 | startAddress = address 62 | elif address != endAddress: 63 | raise Exception( "Data is not continuous on line {}: Expecting address {}, got {}".format(count, endAddress, address)) 64 | 65 | endAddress = address+byteCount 66 | 67 | assembler = " .DB "; 68 | 69 | for index in range(9, len(line)-2, 2): 70 | byte = int( line[index: index+2], 16) 71 | if index > 9: 72 | assembler += ", " 73 | assembler += "0{:02X}h".format(byte) 74 | 75 | assembler += "\n"; 76 | output.append(assembler) 77 | elif recordType == 0x01: # EOF 78 | # Something 79 | print("Got end of file") 80 | if ended: 81 | raise Exception("More than one end of file on line {}".format(count)) 82 | ended = True 83 | else: 84 | raise Exception( "Unhandled record type {} on line {}".format(recordType, count)) 85 | 86 | # print("Line{}: {} = {} {}".format(count, checksum, expected, line)) 87 | else: 88 | raise Exception( "Error - invalid line at {}: {}".format(count, line) ) 89 | 90 | if not ended: 91 | raise Exception("Missing end of file record") 92 | 93 | print("Start address {:04x}, endAddress {:04x} - total bytes {}".format(startAddress, endAddress-1, endAddress-startAddress)) 94 | 95 | output.insert(1, "; Start address {:04X}, endAddress {:04X} - total bytes {}\n;\n".format(startAddress, endAddress-1, endAddress-startAddress)) 96 | output.insert(2, " .DW 0{:04x}h, 0{:04X}h ; Start, length \n\n".format(startAddress, endAddress-startAddress)) 97 | file1 = open(outfile, 'w') 98 | file1.writelines(output) 99 | file1.close() 100 | -------------------------------------------------------------------------------- /firmware/i2c.asm: -------------------------------------------------------------------------------- 1 | ; ============================================ I2C Routines ================================================= 2 | ; Software driven I2C for Z80 PIO 3 | ; 4 | ; Assume I2C clock is on Port B bit 6 5 | ; data is on Port B bit 7 6 | ; 7 | ; 8 | ; Copyright (c) 2023 Andy Toone for Feersum Technology Ltd. 9 | ; 10 | ; Part of the MicroBeast Z80 kit computer project. Support hobby electronics. 11 | ; 12 | ; Permission is hereby granted, free of charge, to any person obtaining a copy 13 | ; of this software and associated documentation files (the "Software"), to deal 14 | ; in the Software without restriction, including without limitation the rights 15 | ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | ; copies of the Software, and to permit persons to whom the Software is 17 | ; furnished to do so, subject to the following conditions: 18 | ; 19 | ; The above copyright notice and this permission notice shall be included in all 20 | ; copies or substantial portions of the Software. 21 | ; 22 | ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | ; SOFTWARE. 29 | ; 30 | .MODULE i2c 31 | 32 | init_portb LD A, PIO_MODE_3 ; Port B mode 3 33 | LD (port_b_mode), A 34 | OUT (PIO_B_CTRL), A 35 | 36 | LD A, PORT_B_IOMASK ; 37 | LD (port_b_dir), A 38 | OUT (PIO_B_CTRL), A 39 | 40 | LD A, 03Fh ; All bits high apart from D7, D6 41 | LD (port_b_data),A 42 | OUT (PIO_B_DATA), A ; Changing D7 or D6 to an output will drive the lines low 43 | RET 44 | 45 | ; Reset the bus 46 | ; 47 | ; Uses A, B, D 48 | i2c_bus_reset LD B, 0ah ; ten cycles 49 | _loop_b CALL i2c_scl_cycle 50 | DJNZ _loop_b 51 | CALL i2c_scl_high 52 | LD B, 0F0h 53 | DJNZ $ 54 | RET 55 | 56 | ; 57 | ; Uses A 58 | i2c_start CALL i2c_sda_high 59 | CALL i2c_scl_high 60 | CALL i2c_sda_low ; Drive data low 61 | JP i2c_scl_low ; Drive clock low 62 | 63 | 64 | ; 65 | ; Read a byte from Device address H, Register L into A 66 | ; Calls i2c_start, sets address, reads byte and then calls i2c_stop 67 | ; Returns With Carry SET and A containing the register value, or Carry CLEAR if no acknowledge 68 | ; Uses A, B, C, D, H, L 69 | ; Preserves H, L 70 | i2c_read_byte CALL i2c_read_from 71 | ; Fall through into stop 72 | 73 | ; 74 | ; Uses A 75 | i2c_stop CALL i2c_sda_low ; Drive data low 76 | CALL i2c_scl_high 77 | JP i2c_sda_high 78 | 79 | ; Write a byte in C to Device address H, register L 80 | ; Returns with Carry SET if OK, CLEAR if no acknowledgement 81 | ; Calls i2c_stop when done.. 82 | ; 83 | ; Preserves H, L 84 | i2c_write_byte PUSH BC 85 | CALL i2c_write_to 86 | POP BC 87 | JP NC, i2c_stop 88 | LD A, C 89 | CALL i2c_write 90 | JR i2c_stop 91 | 92 | ; 93 | ; Read a byte from Device address H, Register L 94 | ; Calls i2c_start, but does NOT call i2c_stop 95 | ; Returns With Carry SET and A containing the register value, or Carry CLEAR if no acknowledge 96 | ; Uses A, B, C, D, H, L 97 | ; Preserves H, L 98 | i2c_read_from CALL i2c_start 99 | LD A, H 100 | CALL i2c_address_w 101 | JR NC, _read_end 102 | LD A, L 103 | CALL i2c_write 104 | JR NC, _read_end 105 | LD B, 50 106 | _read_pause DJNZ _read_pause 107 | CALL i2c_start 108 | LD A, H 109 | CALL i2c_address_r 110 | JR NC, _read_end 111 | CALL i2c_read 112 | SCF 113 | _read_end RET 114 | 115 | 116 | ; 117 | ; Prepare to write to Device address H, Register L 118 | ; Calls i2c_start, but does NOT call i2c_stop 119 | ; Returns with Carry SET if OK, CLEAR if no acknowledgement 120 | ; 121 | ; Preserves H, L 122 | i2c_write_to CALL i2c_start 123 | LD A, H 124 | CALL i2c_address_w 125 | RET NC 126 | LD A, L 127 | JP i2c_write 128 | 129 | ; Start reading from device address held in A 130 | ; 131 | ; Uses A, B, C, D 132 | i2c_address_r SLA A 133 | OR 1 134 | JR i2c_write 135 | 136 | ; Start writing to device address held in A 137 | ; 138 | ; Uses A, B, C, D 139 | i2c_address_w SLA A 140 | 141 | ; Write A as a byte to i2c bus 142 | ; Returns Carry CLEAR if no acknowledge 143 | ; 144 | ; Uses A, B, C, D 145 | i2c_write PUSH HL 146 | LD HL, (port_b_mode) ; L = port_b_mode, H = port_b_dir 147 | LD D, A 148 | 149 | LD A, ~(I2C_DATA_MASK|I2C_CLK_MASK) ; Set SDA and SCL (port_b_dir bit) LOW 150 | AND H 151 | SLA A 152 | LD H, A 153 | 154 | LD C, PIO_B_CTRL 155 | LD B, 8 156 | 157 | _fast_loop LD A, H 158 | SLA D 159 | RR A 160 | OUT (C),L 161 | OUT (PIO_B_CTRL), A 162 | 163 | OR I2C_CLK_MASK 164 | OUT (C), L 165 | OUT (PIO_B_CTRL), A ; Clock high 166 | 167 | XOR I2C_CLK_MASK 168 | OUT (C), L 169 | OUT (PIO_B_CTRL),A ; Clock low 170 | DJNZ _fast_loop 171 | 172 | LD A, H 173 | SCF 174 | RR A 175 | OUT (C),L ; Release SDA 176 | OUT (PIO_B_CTRL), A 177 | 178 | OR I2C_CLK_MASK 179 | OUT (C), L 180 | OUT (PIO_B_CTRL), A ; Clock high 181 | 182 | OUT (C), L 183 | XOR I2C_CLK_MASK 184 | LD L, A 185 | LD (port_b_dir), A 186 | 187 | IN A, (PIO_B_DATA) ; Read ACK 188 | OUT (C),L ; Clock low 189 | 190 | POP HL 191 | 192 | BIT I2C_DATA_BIT, D ; D contains acknowledge bit 193 | SCF 194 | RET Z ; Return with carry set if acknowledge bit is low 195 | 196 | CALL i2c_stop ; Stop bus if error 197 | SCF 198 | CCF 199 | RET ; Clear carry if acknowledge is high 200 | 201 | ; Read byte from i2C into A, without ACK 202 | ; 203 | ; Uses A, B, C, D 204 | i2c_read LD B, 8h 205 | _loop_r IN A, (PIO_B_DATA) 206 | SCF 207 | BIT I2C_DATA_BIT, A 208 | JR NZ, _data_high 209 | CCF 210 | _data_high RL C 211 | CALL i2c_scl_cycle 212 | DJNZ _loop_r 213 | ; CALL i2c_scl_cycle 214 | 215 | LD A, C 216 | RET 217 | 218 | ; 219 | ; Send an ACK.. 220 | ; 221 | i2c_ack CALL i2c_sda_low 222 | CALL i2c_scl_cycle 223 | JR i2c_sda_high 224 | 225 | ; 226 | ; Send a byte in A, returning the ACK state in D 227 | ; Uses A, B, C, 228 | ; 229 | i2c_send_bytez 230 | RET 231 | 232 | ; SCL/SDA toggle routines 233 | ; 234 | ; All use A 235 | i2c_scl_low LD A, (port_b_mode) 236 | OUT (PIO_B_CTRL), A 237 | 238 | LD A, (port_b_dir) 239 | RES I2C_CLK_BIT, A 240 | OUT (PIO_B_CTRL), A 241 | LD (port_b_dir), A 242 | RET 243 | 244 | i2c_sda_high LD A, (port_b_mode) 245 | OUT (PIO_B_CTRL), A 246 | 247 | LD A, (port_b_dir) 248 | SET I2C_DATA_BIT, A 249 | OUT (PIO_B_CTRL), A 250 | LD (port_b_dir), A 251 | RET 252 | 253 | i2c_sda_low LD A, (port_b_mode) 254 | OUT (PIO_B_CTRL), A 255 | 256 | LD A, (port_b_dir) 257 | RES I2C_DATA_BIT, A 258 | OUT (PIO_B_CTRL), A 259 | LD (port_b_dir), A 260 | RET 261 | 262 | i2c_scl_high LD A, (port_b_mode) 263 | OUT (PIO_B_CTRL), A 264 | 265 | LD A, (port_b_dir) 266 | SET I2C_CLK_BIT, A 267 | OUT (PIO_B_CTRL), A 268 | LD (port_b_dir), A 269 | RET 270 | 271 | i2c_scl_cycle PUSH BC 272 | LD BC, PIO_B_CTRL 273 | LD A, (port_b_mode) 274 | LD D, A 275 | LD A, (port_b_dir) 276 | 277 | RES I2C_CLK_BIT, A 278 | LD (port_b_dir), A 279 | OUT (C), D 280 | OUT (PIO_B_CTRL), A 281 | 282 | SET I2C_CLK_BIT, A 283 | OUT (C), D 284 | OUT (PIO_B_CTRL), A 285 | 286 | IN A, (PIO_B_DATA) 287 | OUT (C), D 288 | LD D, A 289 | LD A, (port_b_dir) 290 | OUT (PIO_B_CTRL), A 291 | POP BC 292 | RET 293 | 294 | .MODULE main 295 | -------------------------------------------------------------------------------- /firmware/memory_test.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; Copyright (c) 2023 Andy Toone for Feersum Technology Ltd. 3 | ; 4 | ; Part of the MicroBeast Z80 kit computer project. Support hobby electronics. 5 | ; 6 | ; Permission is hereby granted, free of charge, to any person obtaining a copy 7 | ; of this software and associated documentation files (the "Software"), to deal 8 | ; in the Software without restriction, including without limitation the rights 9 | ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | ; copies of the Software, and to permit persons to whom the Software is 11 | ; furnished to do so, subject to the following conditions: 12 | ; 13 | ; The above copyright notice and this permission notice shall be included in all 14 | ; copies or substantial portions of the Software. 15 | ; 16 | ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | ; SOFTWARE. 23 | ; 24 | .MODULE memory_test 25 | mem_test_start DI 26 | LD BC, 0E9E1h ; POP HL, JP (HL) 27 | LD (0C000h), BC 28 | LD A, (0C000h) 29 | CP 0E1h 30 | JR Z, _locate_ok 31 | 32 | LD A, 'L' 33 | OUT (UART_TX_RX), A 34 | JR $ 35 | 36 | _locate_ok CALL 0C000h 37 | LD A, H 38 | AND 0C0h 39 | LD D, A ; D = our page, to avoid 40 | 41 | LD E, 0 ; E = Which page we're testing 42 | 43 | _test_loop LD A, E ; Don't test the page we're in 44 | ADD A, '0' 45 | OUT (UART_TX_RX), A 46 | AND 03h 47 | RRCA 48 | RRCA 49 | 50 | CP D 51 | 52 | LD C, A 53 | LD A, CARRIAGE_RETURN 54 | OUT (UART_TX_RX), A 55 | LD A, NEWLINE 56 | OUT (UART_TX_RX), A 57 | LD A, C 58 | 59 | JR Z, _test_next 60 | 61 | LD H, A ; HL = start of page 62 | LD L, 0 63 | 64 | LD A, IO_MEM_0 ; C = the IO port controlling it.. 65 | ADD A, E 66 | LD C, A 67 | 68 | LD B, 32 ; B = the physical page we're paging in.. 69 | 70 | _test_page_loop DEC B 71 | LD A, B 72 | ADD A, RAM_PAGE_0 73 | OUT (C), A 74 | 75 | ; Now we have a page in place.. report it and check it can be written and read.. 76 | _wait_uart IN A, (UART_LINE_STATUS) 77 | BIT 5, A 78 | JR Z, _wait_uart ; Bit 5 is set when the UART is ready 79 | 80 | LD A, 'o' 81 | OUT (UART_TX_RX), A 82 | LD A, B 83 | SRL A 84 | SRL A 85 | SRL A 86 | ADD A, '0' 87 | OUT (UART_TX_RX), A 88 | LD A, B 89 | AND 07h 90 | ADD A, '0' 91 | OUT (UART_TX_RX), A 92 | CP '0' 93 | JR NZ, _no_cr 94 | LD A, CARRIAGE_RETURN 95 | OUT (UART_TX_RX), A 96 | LD A, NEWLINE 97 | OUT (UART_TX_RX), A 98 | 99 | _no_cr XOR A 100 | _test_write DEC A 101 | LD (HL), A 102 | CP (HL) 103 | JR NZ, _test_fail 104 | CP B 105 | JR NZ, _test_write 106 | 107 | AND A 108 | JR NZ, _test_page_loop 109 | 110 | _test_next INC E 111 | LD A, 4 112 | CP E 113 | JR NZ, _test_loop 114 | 115 | JR _test_read_page 116 | 117 | _test_fail LD A, 'x' 118 | OUT (UART_TX_RX), A 119 | JR $ 120 | 121 | _test_read_page LD A, 'y' 122 | OUT (UART_TX_RX), A 123 | LD A, CARRIAGE_RETURN 124 | OUT (UART_TX_RX), A 125 | LD A, NEWLINE 126 | OUT (UART_TX_RX), A 127 | 128 | LD B, 0 ; B = the physical page we're paging in.. 129 | 130 | _read_page_loop LD A, B 131 | ADD A, RAM_PAGE_0 132 | OUT (C), A ; C still points to the last valid page we wrote 133 | 134 | LD A, (HL) 135 | CP B 136 | JR NZ, _read_fail 137 | 138 | _wait_uart2 IN A, (UART_LINE_STATUS) 139 | BIT 5, A 140 | JR Z, _wait_uart2 ; Bit 5 is set when the UART is ready 141 | 142 | LD A, B 143 | AND 07h 144 | ADD A, '0' 145 | OUT (UART_TX_RX), A 146 | CP '7' 147 | JR NZ, _no_space 148 | LD A, ' ' 149 | OUT (UART_TX_RX), A 150 | 151 | _no_space INC B 152 | LD A, 32 153 | CP B 154 | JR NZ, _read_page_loop 155 | 156 | LD A, 'y' 157 | _test_complete OUT (UART_TX_RX), A 158 | JR $ 159 | 160 | _read_fail LD A, '!' 161 | JR _test_complete 162 | 163 | .END -------------------------------------------------------------------------------- /firmware/ports.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; Port definintions 3 | ; 4 | ; 5 | ; Copyright (c) 2023 Andy Toone for Feersum Technology Ltd. 6 | ; 7 | ; Part of the MicroBeast Z80 kit computer project. Support hobby electronics. 8 | ; 9 | ; Permission is hereby granted, free of charge, to any person obtaining a copy 10 | ; of this software and associated documentation files (the "Software"), to deal 11 | ; in the Software without restriction, including without limitation the rights 12 | ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | ; copies of the Software, and to permit persons to whom the Software is 14 | ; furnished to do so, subject to the following conditions: 15 | ; 16 | ; The above copyright notice and this permission notice shall be included in all 17 | ; copies or substantial portions of the Software. 18 | ; 19 | ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | ; SOFTWARE. 26 | ; 27 | 28 | BACKSPACE_CHAR .EQU 08h 29 | CARRIAGE_RETURN .EQU 0Dh 30 | NEWLINE .EQU 0Ah 31 | ESCAPE_CHAR .EQU 1Bh 32 | CPM_NUM .EQU 1Fh 33 | 34 | ;=================================== UART ============================================ 35 | UART_TX_RX .EQU 020h ; Read: receiver buffer, Write: transmitter buffer 36 | UART_INT_ENABLE .EQU 021h ; Interrupt enable register 37 | UART_INT_ID .EQU 022h ; Read: Interrupt identification register 38 | UART_FIFO_CTRL .EQU 022h ; Write: FIFO Control register 39 | UART_LINE_CTRL .EQU 023h ; Line control register 40 | UART_MODEM_CTRL .EQU 024h ; Modem control 41 | UART_LINE_STATUS .EQU 025h ; Line status 42 | UART_MODEM_STATUS .EQU 026h ; Modem status 43 | UART_SCRATCH .EQU 027h ; Scratch register 44 | 45 | ;==================================== PIO ============================================ 46 | PIO_A_DATA .EQU 010h 47 | PIO_A_CTRL .EQU 012h 48 | 49 | PIO_B_DATA .EQU 011h 50 | PIO_B_CTRL .EQU 013h 51 | 52 | PIO_MODE_0 .EQU 00Fh ; Mode 0: All outputs 53 | PIO_MODE_1 .EQU 04fh ; Mode 1: All inputs 54 | PIO_MODE_2 .EQU 080h ; Mode 2 (Port A only): Bi-directional 55 | PIO_MODE_3 .EQU 0CFh ; Mode 3: Per-pin I/O on the given port - write an additional word with bits set (1) for input, reset (0) for output on the matching pin. 56 | 57 | PIO_SET_INTERRUPT .EQU 007h ; Set interrupt control world. By itself, this wil disable interrupts on the given port. OR with the following constants to change this 58 | PIO_ENABLE_INT .EQU 080h ; Enable interrupts on the given port, when OR'd with the PIO_SET_INTERRUPT control word. 59 | PIO_INT_MASK .EQU 010h ; When OR'd with the PIO_SET_INTERRUPT control word, the following word will enable interrupts for pins where the matching bit is zero 60 | 61 | ;================================== AUDIO ============================================ 62 | ; Constants for Audio output 63 | AUDIO_PIO .EQU 1 ; Audio on PIO (rev. 0.1 boards) 64 | AUDIO_UART .EQU 2 ; Audio on UART (rev. 0.2 boards) 65 | 66 | AUDIO_VERSION .EQU AUDIO_UART 67 | 68 | #IF AUDIO_VERSION = AUDIO_PIO 69 | PORT_B_IOMASK .EQU 0EFh ; All inputs, apart from bit 4 (audio out) 70 | AUDIO_MASK .EQU 010h ; Bitmask for audio output on Port B. The bit is set for the output pin. 71 | AUDIO_PORT .EQU PIO_B_DATA 72 | 73 | #ELSE 74 | PORT_B_IOMASK .EQU 0FFh ; All inputs 75 | AUDIO_MASK .EQU 008h ; Bitmask for audio output on UART Out 2. The bit is set for the output pin 76 | AUDIO_PORT .EQU UART_MODEM_CTRL 77 | 78 | #ENDIF 79 | 80 | 81 | ;=================================== MEMORY PAGING =================================== 82 | IO_MEM_0 .EQU 070h ; Page 0: 0000h - 3fffh 83 | IO_MEM_1 .EQU 071h ; Page 1: 4000h - 7fffh 84 | IO_MEM_2 .EQU 072h ; Page 2: 8000h - bfffh 85 | IO_MEM_3 .EQU 073h ; Page 3: c000h - ffffh 86 | 87 | IO_MEM_CTRL .EQU 074h ; Paging enable register 88 | IO_MEM_ENABLE .EQU 1 89 | IO_MEM_DISABLE .EQU 0 90 | 91 | RAM_PAGE_0 .EQU 020h 92 | RAM_PAGE_1 .EQU 021h 93 | RAM_PAGE_2 .EQU 022h 94 | RAM_PAGE_3 .EQU 023h 95 | 96 | RAM_PAGE_16 .EQU 030h 97 | RAM_PAGE_31 .EQU 03Fh 98 | 99 | ROM_PAGE_0 .EQU 000h 100 | ROM_PAGE_16 .EQU 010h 101 | 102 | PAGE_1_START .EQU 4000h 103 | 104 | ;====================================== I2C DEVICES =================================== 105 | I2C_DATA_BIT .equ 7 106 | I2C_CLK_BIT .equ 6 107 | 108 | I2C_DATA_MASK .equ 1 << I2C_DATA_BIT 109 | I2C_CLK_MASK .equ 1 << I2C_CLK_BIT 110 | 111 | ; Display 112 | ;========== 113 | DL_ADDRESS .EQU 050h ; Left Matrix controller I2C address 114 | DR_ADDRESS .EQU 053h ; Right Matrix controller I2C address 115 | 116 | DISP_REG_CRWL .EQU 0FEh ; Command Register write lock 117 | DISP_UNLOCK .EQU 0C5h ; Unlock command 118 | 119 | DISP_DEFAULT_BRIGHTNESS .EQU 080h ; Default brightness 120 | DISP_DIMMED .EQU 018h ; Dimmed 121 | 122 | DISPLAY_WIDTH .EQU 24 ; 24 characters 123 | 124 | ; RTC 125 | ;========== 126 | RTC_ADDRESS .EQU 06fh 127 | 128 | RTC_REG_SEC .EQU 000h ; Also has oscillator enable bit in B7, 1 = run 129 | RTC_REG_MIN .EQU 001h 130 | RTC_REG_HOUR .EQU 002h ; B6: 1 = 12hr/ 0 = 24hr clock (r/w) 131 | ; If 12 hr clock, B5: 1 = PM/ 0 = AM. B4: hour tens. Otherwise B5-4: hour tens, B3-0: hour units 132 | RTC_REG_WKDAY .EQU 003h ; Oscillator status bit in B5, 1 = enabled and running. 133 | ; B4: 1 = power was lost, write 0 to clear (timestamp registers are set) 134 | ; B3: 1 = enable external battery supply (VBAT) 135 | ; B2-0: Weekday, from 1 to 7 136 | RTC_REG_DATE .EQU 004h ; BCD Date (1 to 31) 137 | RTC_REG_MTH .EQU 005h ; B5: 1 = Leap year (read only). B4: month tens, B3-0: month units (Month is 1 to 12) 138 | RTC_REG_YEAR .EQU 006h ; BCD Year 139 | 140 | RTC_REG_CTRL .EQU 007h ; B7: If Square wave and Alarm 0 and Alarm 1 are disabled, sets Output Pin level 141 | ; B6: SQWEN, 1 = Enable square wave on Output Pin, Alarms disabled 142 | ; B5, B4: Alarm 1, 0 Enable. 1 = Alarm is enabled 143 | ; B3: 1 = Use external oscillator 144 | ; B2: CRSTRIM, 1 = Coarse trim mode, Output pin is 64Hz 145 | ; B1-0: If SQWEN = 1 & CRSTRIM = 0, sets Output pin freq. 00 -> 1Hz, 01 -> 4.096kHz, 10 -> 8.192kHz, 11 -> 32.768kHz 146 | RTC_REG_TRIM .EQU 008h ; Trim, initially 0. B7: Sign, 1=Add, 0=Subtract clock cycles. 147 | ; B6-0: Trim amount/2. Applied 1 every minute in fine trim, 128 times a second in coarse trim mode. 0 = disable trim 148 | 149 | RTC_64HZ_ENABLED .EQU 044h ; Value for RTC_REG_CTRL to enable 64Hz interrupt output 150 | 151 | RTC_WEEKDAY_RUNNING .EQU 008h ; Value for RTC_REG_WKDAY for normall running of clock -------------------------------------------------------------------------------- /firmware/shared_data.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; Shared data - common state data for routines 3 | ; 4 | ; 5 | 6 | 7 | ; I2C/Port B routines 8 | port_b_mode .equ 0FF00h 9 | port_b_dir .equ 0FF01h 10 | port_b_data .equ 0FF02h 11 | 12 | ; Boot 13 | boot_mode .equ 0FF03h ; Zero = normal boot, non-zero = delete pressed 14 | temp_byte .equ 0FF04h 15 | 16 | ; Display functions 17 | display_address .equ 0FF05h ; byte - address of the display driver (right or left) being written to 18 | 19 | ; 20 | ; Stuff 21 | timer .equ 0FF06h ; Word 22 | 23 | ; General I/O 24 | ; 25 | ; This MUST start with keyboard_state, and will all be reset to zero when io_init is called 26 | ; 27 | _key_state_size .EQU 8 ; 8 key rollover 28 | 29 | keyboard_state .EQU 0FF08h ; state buffer - 8 bytes containing raw key codes for keys currently pressed 30 | keyboard_pos .EQU 0FF10h ; Internal state 31 | key_shift_state .EQU 0FF12h ; Holds state of shift and control keys in bits 0 and 1 respectively 32 | last_keycode .EQU 0FF13h ; The last keycode that was pressed, for repeats.. 33 | key_repeat_time .EQU 0FF14h ; How many poll events since the key state last changed 34 | 35 | _input_buffer_size .EQU 16 36 | input_buffer .EQU 0FF15h ; 16 byte input buffer. Note wraparound is handled by bitmasks, so don't change this length 37 | input_pos .EQU 0FF25h ; Next read position in input buffer 38 | input_free .EQU 0FF26h ; Next write position in input buffer 39 | input_size .EQU 0FF27h ; Bytes occupied in the input buffer 40 | 41 | io_data_end .EQU 0FF28h ; Byte after IO data block, used to reset values to zero 42 | 43 | control_key_pressed .EQU 0FF29h 44 | 45 | scratch_pad .EQU 0FF2Ah ; 26 byte scratch area used for composing display output (eg. rtc time display etc.) 46 | 47 | temp_data .EQU 0FF44h ; 8 byte general data area 48 | 49 | menu_start .EQU 0FF4Ch ; Start address of current menu definition 50 | menu_item_start .EQU 0FF4Eh ; Start address of first item in menu 51 | menu_count .EQU 0FF50h ; Number of items in menu 52 | menu_index .EQU 0FF51h ; Current menu item 53 | menu_timer .EQU 0FF52h ; Time since menu was displayed 54 | menu_enabled .EQU 0FF53h ; D0 - D7 -> Menu item 1 to 8 set enabled (1) or disabled (0) 55 | 56 | cursor_pos .EQU 0FF54h ; Position of cursor for prompt 57 | 58 | ; 59 | ; Panic codes 60 | ; 61 | PANIC_0001 .EQU 0F001h 62 | PANIC_0002 .EQU 0F002h 63 | PANIC_0003 .EQU 0F003h 64 | PANIC_0004 .EQU 0F004h -------------------------------------------------------------------------------- /firmware/uart.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; UART routines.. 3 | ; 4 | ; Copyright (c) 2023 Andy Toone for Feersum Technology Ltd. 5 | ; 6 | ; Part of the MicroBeast Z80 kit computer project. Support hobby electronics. 7 | ; 8 | ; Permission is hereby granted, free of charge, to any person obtaining a copy 9 | ; of this software and associated documentation files (the "Software"), to deal 10 | ; in the Software without restriction, including without limitation the rights 11 | ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | ; copies of the Software, and to permit persons to whom the Software is 13 | ; furnished to do so, subject to the following conditions: 14 | ; 15 | ; The above copyright notice and this permission notice shall be included in all 16 | ; copies or substantial portions of the Software. 17 | ; 18 | ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | ; SOFTWARE. 25 | ; 26 | .MODULE uart 27 | 28 | ; 29 | ; Baud rates, assuming 1.8432Mhz crystal 30 | ; 31 | UART_9600 .EQU 12 32 | UART_19200 .EQU 6 33 | UART_38400 .EQU 3 34 | 35 | UART_MODE_AUTO .EQU 022h ; Auto flow mode 36 | UART_MODE_NO_FLOW .EQU 000h ; Auto RTS and CTS disabled 37 | UART_MODE_DIAG .EQU 030h ; Loopback mode 38 | 39 | ; 40 | ; Various constants 41 | ; 42 | UART_8N1 .EQU 003h 43 | UART_TIMEOUT .EQU 50000 44 | 45 | _CTS_STATUS_MASK .EQU 010h 46 | 47 | ; 48 | ; Set up the UART. Assume it has had time to settle after reset... 49 | ; 50 | ; 51 | uart_init LD BC, UART_19200 ; B is flow control, 0 -> No auto flow control 52 | 53 | IN A,(UART_MODEM_STATUS) ; If CTS is enabled, assume we can use flow control 54 | AND _CTS_STATUS_MASK 55 | JR Z, _no_listener 56 | 57 | LD B, UART_MODE_AUTO 58 | 59 | _no_listener LD A, 80h ; Divisor Latch Setting Mode 60 | OUT (UART_LINE_CTRL), A ; - entered by writing 1 to bit 7 of LCR 61 | NOP 62 | NOP 63 | LD A, C 64 | OUT (UART_TX_RX), A 65 | NOP 66 | NOP 67 | XOR A 68 | OUT (UART_INT_ENABLE), A 69 | NOP 70 | NOP 71 | 72 | LD A, UART_8N1 ; Set 8N1 and exit divisor latch setting mode 73 | OUT (UART_LINE_CTRL), A 74 | 75 | LD A, 07h ; Enable and clear FIFO registers 76 | OUT (UART_FIFO_CTRL), A 77 | 78 | LD A, B 79 | AND A 80 | JR Z, _no_flowcontrol 81 | 82 | OUT (UART_MODEM_CTRL), A 83 | 84 | _no_flowcontrol NOP 85 | NOP 86 | RET 87 | 88 | ; 89 | ; Send character in A to UART 90 | ; Preserves all registers 91 | ; 92 | ; Carry flag is set on return if the UART send succeeded, clear if it timed out 93 | ; 94 | uart_send PUSH BC 95 | PUSH AF 96 | LD BC, UART_TIMEOUT 97 | _check_ready IN A, (UART_LINE_STATUS) 98 | BIT 5, A 99 | JP NZ, _uart_ready ; Bit 5 is set when the UART is ready 100 | DEC BC 101 | LD A, B 102 | OR C 103 | JP NZ, _check_ready 104 | 105 | POP AF 106 | POP BC 107 | SCF 108 | CCF 109 | RET 110 | 111 | _uart_ready POP AF 112 | POP BC 113 | OUT (UART_TX_RX), A 114 | SCF 115 | RET 116 | 117 | ; 118 | ; Check to see if there are any characters to receive 119 | ; Preserves all registers 120 | ; 121 | ; Returns with carry set if there are characters ready, clear if not 122 | ; 123 | uart_ready PUSH AF 124 | IN A, (UART_LINE_STATUS) 125 | BIT 0, A 126 | JP Z, _not_ready 127 | POP AF 128 | SCF 129 | RET 130 | 131 | _not_ready POP AF 132 | SCF 133 | CCF 134 | RET 135 | 136 | ; 137 | ; Receive a character from the UART in A 138 | ; 139 | ; Returns with a character in A and the carry flag set. If no characters 140 | ; are available, returns with the carry flag clear. 141 | ; 142 | uart_receive IN A, (UART_LINE_STATUS) 143 | BIT 0, A 144 | JP Z, _no_character 145 | IN A, (UART_TX_RX) 146 | SCF 147 | RET 148 | 149 | _no_character SCF 150 | CCF 151 | RET 152 | 153 | .MODULE main -------------------------------------------------------------------------------- /firmware/utils/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## MicroBeast Disk Management 3 | 4 | Use `RESTORE.COM` to fetch a CP\M disk image from Flash (Page `010h`) to RAM disk, "loading" the disk for use. 5 | 6 | Use `WRITE.COM` to write the current RAM disk to Flash, "saving" it for later use. 7 | 8 | ## VideoBeast Support 9 | 10 | Use `VPEEK.COM` to read and write VideoBeast memory and registers (requires VideoBeast expansion) 11 | 12 | Use `VLOAD.COM` to load files into VideoBeast memory. 13 | 14 | As an example, two fonts are included on the bootdisk, `INISGBYT.CH8` and `CUSHION.CH8`. Load them in place of the 15 | standard font (which is at address `8100h`) by typing: `VLOAD CUSHION.CH8 x8100` 16 | 17 | ### Fonts 18 | 19 | The included fonts are from DamienG - website here: https://damieng.com/typography/zx-origins/ 20 | 21 | ## File Transfer 22 | 23 | Use these utilities to send and receive CP/M files over a serial console. They turn a file into a block of hexadecimal text 24 | that can be copied and pasted in most PC terminal software. 25 | 26 | `DOWNLOAD.COM` is by Grant Searle - website here: http://searle.hostei.com/grant/index.html 27 | 28 | `UPLOAD.COM` is by Peacock Media - https://blog.peacockmedia.software/2022/01/uploadcom-for-z80-cpm-usage.html 29 | 30 | Online file converter for DOWLOAD.COM here: https://rc2014.co.uk/filepackage/ 31 | 32 | -------------------------------------------------------------------------------- /firmware/utils/cushion.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atoone/MicroBeast/4c5a9fdd1e71aa5e0d928267e6e1ae4ae0d5ae87/firmware/utils/cushion.ch8 -------------------------------------------------------------------------------- /firmware/utils/download.asm: -------------------------------------------------------------------------------- 1 | ;================================================================================== 2 | ; Contents of this file are copyright Grant Searle 3 | ; HEX routine from Joel Owens. 4 | ; 5 | ; You have permission to use this for NON COMMERCIAL USE ONLY 6 | ; If you wish to use it elsewhere, please include an acknowledgement to myself. 7 | ; 8 | ; http://searle.hostei.com/grant/index.html 9 | ; 10 | ; eMail: home.micros01@btinternet.com 11 | ; 12 | ; If the above don't work, please perform an Internet search to see if I have 13 | ; updated the web page hosting service. 14 | ; 15 | ;================================================================================== 16 | 17 | TPA .EQU 100H 18 | REBOOT .EQU 0H 19 | BDOS .EQU 5H 20 | CONIO .EQU 6 21 | CONINP .EQU 1 22 | CONOUT .EQU 2 23 | PSTRING .EQU 9 24 | MAKEF .EQU 22 25 | CLOSEF .EQU 16 26 | WRITES .EQU 21 27 | DELF .EQU 19 28 | SETUSR .EQU 32 29 | 30 | CR .EQU 0DH 31 | LF .EQU 0AH 32 | 33 | FCB .EQU 05CH 34 | BUFF .EQU 080H 35 | 36 | .ORG TPA 37 | 38 | 39 | LD A,0 40 | LD (buffPos),A 41 | LD (checkSum),A 42 | LD (byteCount),A 43 | LD (printCount),A 44 | LD HL,BUFF 45 | LD (buffPtr),HL 46 | 47 | 48 | WAITLT: CALL GETCHR 49 | CP 'U' 50 | JP Z,SETUSER 51 | CP ':' 52 | JR NZ,WAITLT 53 | 54 | 55 | LD C,DELF 56 | LD DE,FCB 57 | CALL BDOS 58 | 59 | LD C,MAKEF 60 | LD DE,FCB 61 | CALL BDOS 62 | 63 | GETHEX: 64 | CALL GETCHR 65 | CP '>' 66 | JR Z,CLOSE 67 | LD B,A 68 | PUSH BC 69 | CALL GETCHR 70 | POP BC 71 | LD C,A 72 | 73 | CALL BCTOA 74 | 75 | LD B,A 76 | LD A,(checkSum) 77 | ADD A,B 78 | LD (checkSum),A 79 | LD A,(byteCount) 80 | INC A 81 | LD (byteCount),A 82 | 83 | LD A,B 84 | 85 | LD HL,(buffPtr) 86 | 87 | LD (HL),A 88 | INC HL 89 | LD (buffPtr),HL 90 | 91 | LD A,(buffPos) 92 | INC A 93 | LD (buffPos),A 94 | CP 80H 95 | 96 | JR NZ,NOWRITE 97 | 98 | LD C,WRITES 99 | LD DE,FCB 100 | CALL BDOS 101 | LD A,'.' 102 | CALL PUTCHR 103 | 104 | ; New line every 8K (64 dots) 105 | LD A,(printCount) 106 | INC A 107 | CP 64 108 | JR NZ,noCRLF 109 | LD (printCount),A 110 | LD A,CR 111 | CALL PUTCHR 112 | LD A,LF 113 | CALL PUTCHR 114 | LD A,0 115 | noCRLF: LD (printCount),A 116 | 117 | LD HL,BUFF 118 | LD (buffPtr),HL 119 | 120 | LD A,0 121 | LD (buffPos),A 122 | NOWRITE: 123 | JR GETHEX 124 | 125 | 126 | CLOSE: 127 | 128 | LD A,(buffPos) 129 | CP 0 130 | JR Z,NOWRITE2 131 | 132 | LD C,WRITES 133 | LD DE,FCB 134 | CALL BDOS 135 | LD A,'.' 136 | CALL PUTCHR 137 | 138 | NOWRITE2: 139 | LD C,CLOSEF 140 | LD DE,FCB 141 | CALL BDOS 142 | 143 | ; Byte count (lower 8 bits) 144 | CALL GETCHR 145 | LD B,A 146 | PUSH BC 147 | CALL GETCHR 148 | POP BC 149 | LD C,A 150 | 151 | CALL BCTOA 152 | LD B,A 153 | LD A,(byteCount) 154 | SUB B 155 | CP 0 156 | JR Z,byteCountOK 157 | 158 | LD A,CR 159 | CALL PUTCHR 160 | LD A,LF 161 | CALL PUTCHR 162 | 163 | LD DE,countErrMess 164 | LD C,PSTRING 165 | CALL BDOS 166 | 167 | ; Sink remaining 2 bytes 168 | CALL GETCHR 169 | CALL GETCHR 170 | 171 | JR FINISH 172 | 173 | byteCountOK: 174 | 175 | ; Checksum 176 | CALL GETCHR 177 | LD B,A 178 | PUSH BC 179 | CALL GETCHR 180 | POP BC 181 | LD C,A 182 | 183 | CALL BCTOA 184 | LD B,A 185 | LD A,(checkSum) 186 | SUB B 187 | CP 0 188 | JR Z,checksumOK 189 | 190 | LD A,CR 191 | CALL PUTCHR 192 | LD A,LF 193 | CALL PUTCHR 194 | 195 | LD DE,chkErrMess 196 | LD C,PSTRING 197 | CALL BDOS 198 | JR FINISH 199 | 200 | checksumOK: 201 | LD A,CR 202 | CALL PUTCHR 203 | LD A,LF 204 | CALL PUTCHR 205 | 206 | LD DE,OKMess 207 | LD C,PSTRING 208 | CALL BDOS 209 | 210 | 211 | 212 | FINISH: 213 | LD C,SETUSR 214 | LD E,0 215 | CALL BDOS 216 | 217 | JP REBOOT 218 | 219 | 220 | SETUSER: 221 | CALL GETCHR 222 | CALL HEX2VAL 223 | LD E,A 224 | LD C,SETUSR 225 | CALL BDOS 226 | JP WAITLT 227 | 228 | 229 | ; Get a char into A 230 | ;GETCHR: LD C,CONINP 231 | ; CALL BDOS 232 | ; RET 233 | 234 | ; Wait for a char into A (no echo) 235 | GETCHR: 236 | LD E,$FF 237 | LD C,CONIO 238 | CALL BDOS 239 | CP 0 240 | JR Z,GETCHR 241 | RET 242 | 243 | ; Write A to output 244 | PUTCHR: LD C,CONOUT 245 | LD E,A 246 | CALL BDOS 247 | RET 248 | 249 | 250 | ;------------------------------------------------------------------------------ 251 | ; Convert ASCII characters in B C registers to a byte value in A 252 | ;------------------------------------------------------------------------------ 253 | BCTOA LD A,B ; Move the hi order byte to A 254 | SUB $30 ; Take it down from Ascii 255 | CP $0A ; Are we in the 0-9 range here? 256 | JR C,BCTOA1 ; If so, get the next nybble 257 | SUB $07 ; But if A-F, take it down some more 258 | BCTOA1 RLCA ; Rotate the nybble from low to high 259 | RLCA ; One bit at a time 260 | RLCA ; Until we 261 | RLCA ; Get there with it 262 | LD B,A ; Save the converted high nybble 263 | LD A,C ; Now get the low order byte 264 | SUB $30 ; Convert it down from Ascii 265 | CP $0A ; 0-9 at this point? 266 | JR C,BCTOA2 ; Good enough then, but 267 | SUB $07 ; Take off 7 more if it's A-F 268 | BCTOA2 ADD A,B ; Add in the high order nybble 269 | RET 270 | 271 | ; Change Hex in A to actual value in A 272 | HEX2VAL SUB $30 273 | CP $0A 274 | RET C 275 | SUB $07 276 | RET 277 | 278 | 279 | buffPos .DB 0H 280 | buffPtr .DW 0000H 281 | printCount .DB 0H 282 | checkSum .DB 0H 283 | byteCount .DB 0H 284 | OKMess .BYTE "OK$" 285 | chkErrMess .BYTE "======Checksum Error======$" 286 | countErrMess .BYTE "======File Length Error======$" 287 | .END 288 | -------------------------------------------------------------------------------- /firmware/utils/download.com: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atoone/MicroBeast/4c5a9fdd1e71aa5e0d928267e6e1ae4ae0d5ae87/firmware/utils/download.com -------------------------------------------------------------------------------- /firmware/utils/insigbyt.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atoone/MicroBeast/4c5a9fdd1e71aa5e0d928267e6e1ae4ae0d5ae87/firmware/utils/insigbyt.ch8 -------------------------------------------------------------------------------- /firmware/utils/restore.com: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atoone/MicroBeast/4c5a9fdd1e71aa5e0d928267e6e1ae4ae0d5ae87/firmware/utils/restore.com -------------------------------------------------------------------------------- /firmware/utils/upload.com: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atoone/MicroBeast/4c5a9fdd1e71aa5e0d928267e6e1ae4ae0d5ae87/firmware/utils/upload.com -------------------------------------------------------------------------------- /firmware/utils/vload.com: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atoone/MicroBeast/4c5a9fdd1e71aa5e0d928267e6e1ae4ae0d5ae87/firmware/utils/vload.com -------------------------------------------------------------------------------- /firmware/utils/vpeek.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; VPEEK - Videobeast peek and poke utility 3 | ; 4 | ; Copyright (c) 2023 Andy Toone for Feersum Technology Ltd. 5 | ; 6 | ; Part of the MicroBeast Z80 kit computer project. Support hobby electronics. 7 | ; 8 | ; Permission is hereby granted, free of charge, to any person obtaining a copy 9 | ; of this software and associated documentation files (the "Software"), to deal 10 | ; in the Software without restriction, including without limitation the rights 11 | ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | ; copies of the Software, and to permit persons to whom the Software is 13 | ; furnished to do so, subject to the following conditions: 14 | ; 15 | ; The above copyright notice and this permission notice shall be included in all 16 | ; copies or substantial portions of the Software. 17 | ; 18 | ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | ; SOFTWARE. 25 | ; 26 | 27 | ; 28 | ; Command line: VPEEK hex_address 29 | ; 30 | ; With just hex_addres specified, VPEEK will list the values at the given hex address in the current VideoBeast page. 31 | ; Use to read registers (unlocks and re-locks register access). Enter for more values, any other key to exit. 32 | ; Add one or more values (space or comma separated) to set values from the given address 33 | ; Use to exit immediately without prompting 34 | ; 35 | ; 36 | .ORG 0100h 37 | 38 | .INCLUDE "beastos/bios.inc" 39 | 40 | CMD_LEN .EQU 00080h 41 | CMD_START .EQU 00081h 42 | 43 | IO_PAGE_1 .EQU 071h ; Page 1: 4000h - 7fffh 44 | 45 | VB_UNLOCK .EQU 0F3h ; Unlock register write 46 | 47 | VBASE .EQU 04000h 48 | 49 | VB_MODE .EQU VBASE + 03FFFh 50 | VB_REGISTERS_LOCKED .EQU VBASE + 03FFEh 51 | 52 | VB_REGISTERS_H .EQU (VBASE >> 8) + 03Fh 53 | 54 | LD (old_stack), SP 55 | LD SP, old_stack 56 | 57 | XOR A 58 | LD (cmd_mode), A 59 | LD A, (CMD_LEN) 60 | OR A 61 | JR NZ, _has_params 62 | 63 | _show_help LD DE, help_message 64 | _exit_message LD C, BDOS_PRINTSTRING 65 | CALL BDOS 66 | _finish LD SP, (old_stack) 67 | RET 68 | 69 | _has_params LD B, A 70 | LD HL, CMD_START 71 | _param_loop LD A, (HL) 72 | INC HL 73 | CP 64 74 | JR C, _not_alpha 75 | OR 020h ; To lowercase 76 | _not_alpha CP 'r' 77 | JR NZ, _not_register 78 | LD A, (cmd_mode) 79 | AND A 80 | LD DE, r_error_message 81 | JR NZ, _exit_message 82 | LD A, (cmd_options) 83 | OR OPT_REGISTER 84 | _set_param LD (cmd_options), A 85 | JR _next_param 86 | 87 | _not_register CP 'x' 88 | JR NZ, _not_exit 89 | LD A, (cmd_mode) 90 | AND A 91 | LD DE, x_error_message 92 | JR NZ, _exit_message 93 | LD A, (cmd_options) 94 | OR OPT_EXIT 95 | JR _set_param 96 | 97 | _not_exit CP ' ' 98 | JR Z, _next_param 99 | CP ',' 100 | JR Z, _next_param 101 | JR _param_value 102 | 103 | _next_param DJNZ _param_loop 104 | LD A, (cmd_mode) 105 | AND A 106 | 107 | JR Z, _show_help 108 | 109 | RET 110 | 111 | _show_value_error LD DE, value_error_message 112 | JR _exit_message 113 | 114 | _show_long_error LD DE, long_error_message 115 | JR _exit_message 116 | 117 | _param_value LD DE, 0 118 | EX DE, HL 119 | LD C, 5 120 | JR _value_go 121 | 122 | _value_loop LD A, (DE) 123 | 124 | CP ' ' 125 | JR Z, _use_value 126 | CP ',' 127 | JR Z, _use_value 128 | INC DE 129 | 130 | _value_go DEC C 131 | JR Z, _show_long_error 132 | 133 | CP '0' 134 | JR C, _show_value_error 135 | 136 | CP ':' 137 | JR C, _param_digit 138 | 139 | OR 020h ; Lower cases 140 | CP 'a' 141 | JR C, _show_value_error 142 | 143 | CP 'g' 144 | JR NC, _show_value_error 145 | 146 | SUB 'a'-10 147 | JR _use_digit 148 | _param_digit SUB '0' 149 | _use_digit AND 0Fh 150 | ADD HL, HL 151 | ADD HL, HL 152 | ADD HL, HL 153 | ADD HL, HL 154 | OR L 155 | LD L, A 156 | 157 | DJNZ _value_loop 158 | 159 | _use_value LD A, (cmd_mode) 160 | AND A 161 | JR NZ, _write_value 162 | INC A 163 | LD (cmd_mode), A 164 | LD (cmd_address), HL 165 | LD (cmd_write_address), HL 166 | LD A, B 167 | AND A 168 | JR Z, _display_values 169 | EX DE, HL 170 | JP _param_loop 171 | 172 | _write_value LD A, H 173 | AND A 174 | JR NZ, _show_long_error 175 | LD C, L 176 | LD HL, (cmd_write_address) 177 | 178 | CALL access_videobeast 179 | 180 | LD A, (cmd_options) 181 | AND OPT_REGISTER 182 | JR Z, _full_address 183 | LD H, VB_REGISTERS_H 184 | 185 | LD A, VB_UNLOCK 186 | LD (VB_REGISTERS_LOCKED), A 187 | 188 | _full_address LD A, C 189 | LD (HL), A 190 | INC HL 191 | LD (cmd_write_address), HL 192 | 193 | CALL restore_videobeast 194 | EX DE, HL 195 | 196 | LD A, B 197 | AND A 198 | JP NZ, _param_loop 199 | 200 | ; 201 | ; ------------------------- Display the values from the selected address ------------------------- 202 | ; 203 | _display_values LD A, (cmd_options) ; TODO: Always start at 0/8 offset? 204 | AND OPT_REGISTER 205 | JR Z, _disp_address 206 | 207 | LD DE, disp_r_message 208 | LD C, BDOS_PRINTSTRING 209 | CALL BDOS 210 | JR _disp_address_low 211 | 212 | _disp_address LD A, (cmd_address+1) 213 | CALL display_hex 214 | _disp_address_low LD A, (cmd_address) ; Fix address to 8 byte steps 215 | AND 0F8h 216 | LD (cmd_address), A 217 | CALL display_hex 218 | 219 | LD E, ' ' 220 | LD C, BDOS_CONOUT 221 | CALL BDOS 222 | 223 | CALL access_videobeast 224 | 225 | LD B, 8 226 | LD HL, (cmd_address) 227 | 228 | LD A, (cmd_options) 229 | AND OPT_REGISTER 230 | JR Z, _disp_loop 231 | LD H, VB_REGISTERS_H 232 | 233 | LD A, VB_UNLOCK 234 | LD (VB_REGISTERS_LOCKED), A 235 | 236 | _disp_loop LD A, (HL) 237 | CALL display_hex 238 | 239 | INC HL 240 | DJNZ _disp_loop 241 | CALL restore_videobeast 242 | 243 | LD A, (cmd_options) 244 | AND OPT_EXIT 245 | JP NZ, _finish 246 | 247 | _wait_key LD E, 0FFh 248 | LD C, BDOS_CONIO 249 | CALL BDOS 250 | AND A 251 | JR Z, _wait_key 252 | CP 13 253 | JP NZ, _finish 254 | 255 | LD BC, 8 256 | LD HL, (cmd_address) 257 | ADD HL, BC 258 | LD (cmd_address), HL 259 | 260 | LD DE, disp_newline 261 | LD C, BDOS_PRINTSTRING 262 | CALL BDOS 263 | 264 | JR _display_values 265 | 266 | display_hex PUSH HL 267 | PUSH BC 268 | 269 | PUSH AF 270 | SRA A 271 | SRA A 272 | SRA A 273 | SRA A 274 | CALL to_hex 275 | 276 | LD E, A 277 | LD C, BDOS_CONOUT 278 | CALL BDOS 279 | POP AF 280 | CALL to_hex 281 | 282 | LD E, A 283 | LD C, BDOS_CONOUT 284 | CALL BDOS 285 | 286 | POP BC 287 | POP HL 288 | RET 289 | 290 | ; Returns the low nibble of A as a hex digit 291 | ; 292 | to_hex AND 00Fh ;LOW NIBBLE ONLY 293 | ADD A,090h 294 | DAA 295 | ADC A,040h 296 | DAA 297 | RET 298 | 299 | access_videobeast DI 300 | PUSH HL 301 | PUSH BC 302 | PUSH DE 303 | LD C, 1 304 | CALL MBB_GET_PAGE 305 | LD (old_page),A 306 | LD A, 1 307 | LD E, 040h 308 | CALL MBB_SET_PAGE 309 | 310 | LD A, (VB_REGISTERS_LOCKED) 311 | LD (lock_status), A 312 | POP DE 313 | POP BC 314 | POP HL 315 | RET 316 | 317 | restore_videobeast LD A, (lock_status) 318 | LD (VB_REGISTERS_LOCKED), A 319 | 320 | PUSH DE 321 | PUSH BC 322 | 323 | LD A, (old_page) 324 | LD E, A 325 | LD A, 1 326 | CALL MBB_SET_PAGE 327 | POP BC 328 | POP DE 329 | EI 330 | RET 331 | 332 | cmd_mode .DB 0 333 | cmd_options .DB 0 334 | cmd_address .DW 0 335 | cmd_write_address .DW 0 336 | 337 | lock_status .DB 0 338 | old_page .DB 0 339 | 340 | stack_space .BLOCK 32 ; 16 deep stack.. 341 | old_stack .DW 0 342 | 343 | OPT_REGISTER .EQU 01h 344 | OPT_EXIT .EQU 02h 345 | 346 | disp_r_message .DB "R $" 347 | 348 | disp_newline .DB "\n\r$" 349 | 350 | r_error_message .DB "ERROR: Unexpected 'r' parameter.$" 351 | 352 | x_error_message .DB "ERROR: Unexpected 'x' parameter.$" 353 | 354 | value_error_message .DB "ERROR: Invalid hex value. Use 0-9, A-F.$" 355 | 356 | long_error_message .DB "ERROR: Have value too long$" 357 | 358 | help_message .DB "VPEEK: VideoBeast RAM Read/Write\n\r" 359 | .DB " Usage:\n\r" 360 | .DB " VPEEK [r|x] HEX [value] [value..]\n\r\n" 361 | .DB " Options:\n\r" 362 | .DB " r : Access VideoBeast registers 00-FF\n\r" 363 | .DB " x : Exit without prompting\n\r\n" 364 | .DB " Add values (space or comma separated) to write.\n\r" 365 | .DB "$" 366 | 367 | 368 | .END -------------------------------------------------------------------------------- /firmware/utils/vpeek.com: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atoone/MicroBeast/4c5a9fdd1e71aa5e0d928267e6e1ae4ae0d5ae87/firmware/utils/vpeek.com -------------------------------------------------------------------------------- /firmware/utils/write.com: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atoone/MicroBeast/4c5a9fdd1e71aa5e0d928267e6e1ae4ae0d5ae87/firmware/utils/write.com -------------------------------------------------------------------------------- /firmware/utils/z80asm (SLR Systems).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atoone/MicroBeast/4c5a9fdd1e71aa5e0d928267e6e1ae4ae0d5ae87/firmware/utils/z80asm (SLR Systems).pdf -------------------------------------------------------------------------------- /firmware/utils/z80asm.com: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atoone/MicroBeast/4c5a9fdd1e71aa5e0d928267e6e1ae4ae0d5ae87/firmware/utils/z80asm.com -------------------------------------------------------------------------------- /reference/16c550.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atoone/MicroBeast/4c5a9fdd1e71aa5e0d928267e6e1ae4ae0d5ae87/reference/16c550.pdf -------------------------------------------------------------------------------- /reference/MCP7940N_RTC.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atoone/MicroBeast/4c5a9fdd1e71aa5e0d928267e6e1ae4ae0d5ae87/reference/MCP7940N_RTC.pdf -------------------------------------------------------------------------------- /reference/z80piomn.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atoone/MicroBeast/4c5a9fdd1e71aa5e0d928267e6e1ae4ae0d5ae87/reference/z80piomn.pdf -------------------------------------------------------------------------------- /src/examples/flash.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; Flash update routines 3 | ; 4 | ; Note that any memory write operations *at all* during flash updates will cancel the current operation. 5 | ; That means no data can be stored to memory, no stack operations (call, push), no interrupts. 6 | ; 7 | ; 8 | .MODULE flash 9 | 10 | _cmd_1_addr .EQU 05555h 11 | _cmd_2_addr .EQU 02AAAh 12 | 13 | _bank_mask .EQU 03FFFh ; One memory bank is 14 bits -> 16Kb 14 | _sector_mask .EQU 00FFFh ; A sector is 12 bits -> 4Kb 15 | 16 | _cmd_1_addr_bank .EQU _cmd_1_addr >> 14 17 | _cmd_2_addr_bank .EQU _cmd_2_addr >> 14 18 | _cmd_3_addr_bank .EQU _cmd_1_addr_bank 19 | _cmd_4_addr_bank .EQU _cmd_1_addr_bank 20 | _cmd_5_addr_bank .EQU _cmd_2_addr_bank 21 | 22 | _cmd_1_logical_addr .EQU _cmd_1_addr & _bank_mask 23 | _cmd_2_logical_addr .EQU _cmd_2_addr & _bank_mask 24 | _cmd_3_logical_addr .EQU _cmd_1_logical_addr 25 | _cmd_4_logical_addr .EQU _cmd_1_logical_addr 26 | _cmd_5_logical_addr .EQU _cmd_2_logical_addr 27 | 28 | _cmd_1_data .EQU 0AAh 29 | _cmd_2_data .EQU 055h 30 | _cmd_3_data_write .EQU 0A0h 31 | _cmd_3_data_erase .EQU 080h 32 | _cmd_4_data .EQU 0AAh 33 | _cmd_5_data .EQU 055h 34 | 35 | _cmd_6_data_erase .EQU 030h 36 | 37 | ; 38 | ; Enter with A -> 7 bit index of 4K sector to be erased. 39 | ; 40 | ; Preserves BC, DE, HL 41 | ; 42 | ; Note this uses bank 0, and leaves it configured for the page containing the erased sector 43 | ; 44 | ; Typical time to erase sector ~18ms 45 | ; 46 | flash_sector_erase DI ; Disable interrupts 47 | PUSH HL 48 | PUSH BC 49 | PUSH DE 50 | 51 | AND 07fh 52 | LD D, A 53 | SRL D 54 | SRL D ; D is now the bank number 55 | 56 | SLA A 57 | SLA A 58 | SLA A 59 | SLA A 60 | AND 030h 61 | LD E, A ; E is the sector within the bank shifted into bits 13 & 12 62 | 63 | LD C, IO_MEM_0 ; Use bank 0 to write to 64 | LD A, _cmd_1_addr_bank 65 | OUT (C), A 66 | LD HL, _cmd_1_logical_addr 67 | LD (HL), _cmd_1_data 68 | 69 | LD A, _cmd_2_addr_bank 70 | OUT (C), A 71 | LD HL, _cmd_2_logical_addr 72 | LD (HL), _cmd_2_data 73 | 74 | LD A, _cmd_3_addr_bank 75 | OUT (C), A 76 | LD HL, _cmd_3_logical_addr 77 | LD (HL), _cmd_3_data_erase 78 | 79 | LD A, _cmd_4_addr_bank 80 | OUT (C), A 81 | LD HL, _cmd_4_logical_addr 82 | LD (HL), _cmd_4_data 83 | 84 | LD A, _cmd_5_addr_bank 85 | OUT (C), A 86 | LD HL, _cmd_5_logical_addr 87 | LD (HL), _cmd_5_data 88 | 89 | OUT (C), D ; Switch to the bank containing our sector 90 | LD H, E ; And write the sector bits as an address (bits 0-11 are ignored) 91 | LD (HL), _cmd_6_data_erase 92 | 93 | _wait_erase LD A,(HL) 94 | RLC A 95 | JR NC, _wait_erase 96 | 97 | POP DE 98 | POP BC 99 | POP HL 100 | EI 101 | RET 102 | 103 | ; 104 | ; Enter with A -> Byte to write 105 | ; D -> 7 bit index of 4K sector being written 106 | ; HL -> 12 bit address of byte within sector 107 | ; 108 | ; Preserves D, HL 109 | ; Uses A, BC, E 110 | ; 111 | ; Typical time to erase byte ~14us 112 | ; 113 | flash_write_byte DI 114 | LD E, A ; Preserve our byte 115 | 116 | LD A, H ; Make sure HL is within our sector 117 | AND _sector_mask >> 8 118 | LD H, A 119 | 120 | LD A, D ; Make sure D is a valid sector index 121 | AND 07fh 122 | LD D, A 123 | LD B, A 124 | 125 | LD A, D ; Get the bottom 2 bits of our sector index.. 126 | AND 03h 127 | SLA A 128 | SLA A 129 | SLA A 130 | SLA A 131 | OR H 132 | LD H, A ; ..and OR them into H to get a 14 bit address within our bank 133 | 134 | SRL D 135 | SRL D ; D is now our bank number 136 | 137 | PUSH HL 138 | 139 | LD C, IO_MEM_0 ; Use bank 0 to write to 140 | LD A, _cmd_1_addr_bank 141 | OUT (C), A 142 | LD HL, _cmd_1_logical_addr 143 | LD (HL), _cmd_1_data 144 | 145 | LD A, _cmd_2_addr_bank 146 | OUT (C), A 147 | LD HL, _cmd_2_logical_addr 148 | LD (HL), _cmd_2_data 149 | 150 | LD A, _cmd_3_addr_bank 151 | OUT (C), A 152 | LD HL, _cmd_3_logical_addr 153 | LD (HL), _cmd_3_data_write 154 | 155 | OUT (C), D 156 | POP HL 157 | LD (HL), E 158 | 159 | _wait_byte LD A, (HL) 160 | XOR E 161 | RLC A 162 | JR NC, _wait_byte 163 | 164 | LD A, H ; Clear bits 13 & 12 to restore HL to sector address.. 165 | AND _sector_mask >> 8 166 | LD H, A 167 | 168 | LD D, B ; And restore D 169 | EI 170 | RET 171 | 172 | ; 173 | ; Write a flash data block. This uses Page 0 to write the data, so the source must be above 4000h 174 | ; 175 | ; D -> 7 bit index of 4K sector being written 176 | ; HL -> Address of source data 177 | ; BC -> bytes to write 178 | ; 179 | 180 | flash_write PUSH IX 181 | PUSH HL 182 | POP IX 183 | LD HL, 0 184 | 185 | _erase_sector ; Lower 12 bits of HL are zero, erase sector before writing bytes 186 | LD A, D 187 | CALL flash_sector_erase 188 | _write_loop LD A, (IX+0) 189 | PUSH BC 190 | CALL flash_write_byte 191 | POP BC 192 | 193 | INC IX 194 | DEC BC 195 | LD A, B 196 | OR C 197 | JR Z, _success 198 | 199 | INC HL 200 | LD A, L 201 | AND A 202 | JR NZ, _write_loop 203 | LD A, H 204 | AND _sector_mask >> 8 205 | LD H, A 206 | JR NZ, _write_loop 207 | 208 | INC D 209 | JR _erase_sector 210 | 211 | _success POP IX 212 | RET 213 | 214 | .MODULE main 215 | -------------------------------------------------------------------------------- /src/examples/i2c.asm: -------------------------------------------------------------------------------- 1 | ; ============================================ I2C Routines ================================================= 2 | ; Software driven I2C for Z80 PIO 3 | ; 4 | ; Assume I2C clock is on Port B bit 6 5 | ; data is on Port B bit 7 6 | ; 7 | 8 | .MODULE i2c 9 | 10 | init_portb LD A, PIO_MODE_3 ; Port B mode 3 11 | LD (port_b_mode), A 12 | OUT (PIO_B_CTRL), A 13 | 14 | LD A, PORT_B_IOMASK ; 15 | LD (port_b_dir), A 16 | OUT (PIO_B_CTRL), A 17 | 18 | LD A, 03Fh ; All bits high apart from D7, D6 19 | LD (port_b_data),A 20 | OUT (PIO_B_DATA), A ; Changing D7 or D6 to an output will drive the lines low 21 | RET 22 | 23 | ; Reset the bus 24 | ; 25 | ; Uses A, B, D 26 | i2c_bus_reset LD B, 0ah ; ten cycles 27 | _loop_b CALL i2c_scl_cycle 28 | DJNZ _loop_b 29 | CALL i2c_scl_high 30 | LD B, 0F0h 31 | DJNZ $ 32 | RET 33 | 34 | ; 35 | ; Uses A 36 | i2c_start CALL i2c_sda_high 37 | CALL i2c_scl_high 38 | CALL i2c_sda_low ; Drive data low 39 | CALL i2c_scl_low ; Drive clock low 40 | RET 41 | 42 | ; 43 | ; Uses A 44 | i2c_stop CALL i2c_sda_low ; Drive data low 45 | CALL i2c_scl_high 46 | CALL i2c_sda_high 47 | RET 48 | 49 | ; 50 | ; Read a byte from Device address H, Register L 51 | ; Calls i2c_start, but does NOT call i2c_stop 52 | ; Returns With Carry SET and A containing the register value, or Carry CLEAR if no acknowledge 53 | ; Uses A, B, C, D, H, L 54 | ; Preserves H, L 55 | i2c_read_from CALL i2c_start 56 | LD A, H 57 | CALL i2c_address_w 58 | JR NC, _read_end 59 | LD A, L 60 | CALL i2c_write 61 | JR NC, _read_end 62 | LD B, 50 63 | _read_pause DJNZ _read_pause 64 | CALL i2c_start 65 | LD A, H 66 | CALL i2c_address_r 67 | JR NC, _read_end 68 | CALL i2c_read 69 | SCF 70 | _read_end RET 71 | 72 | ; 73 | ; Prepare to write to Device address H, Register L 74 | ; Calls i2c_start, but does NOT call i2c_stop 75 | ; Returns with Carry SET if OK, CLEAR if no acknowledgement 76 | ; 77 | ; Preserves H, L 78 | i2c_write_to CALL i2c_start 79 | LD A, H 80 | CALL i2c_address_w 81 | RET NC 82 | LD A, L 83 | CALL i2c_write 84 | RET 85 | 86 | ; Start reading from device address held in A 87 | ; 88 | ; Uses A, B, C, D 89 | i2c_address_r SLA A 90 | OR 1 91 | JR i2c_write 92 | 93 | ; Start writing to device address held in A 94 | ; 95 | ; Uses A, B, C, D 96 | i2c_address_w SLA A 97 | 98 | ; Write A as a byte to i2c bus 99 | ; Returns Carry CLEAR if no acknowledge 100 | ; 101 | ; Uses A, B, C, D 102 | i2c_write CALL i2c_send_byte 103 | BIT I2C_DATA_BIT, D ; D contains acknowledge bit 104 | SCF 105 | RET Z ; Return with carry set if acknowledge bit is low 106 | 107 | CALL i2c_stop ; Stop bus if error 108 | SCF 109 | CCF 110 | RET ; Clear carry if acknowledge is high 111 | 112 | ; Read byte from i2C into A, without ACK 113 | ; 114 | ; Uses A, B, C, D 115 | i2c_read LD B, 8h 116 | _loop_r IN A, (PIO_B_DATA) 117 | SCF 118 | BIT I2C_DATA_BIT, A 119 | JR NZ, _data_high 120 | CCF 121 | _data_high RL C 122 | CALL i2c_scl_cycle 123 | DJNZ _loop_r 124 | ; CALL i2c_scl_cycle 125 | 126 | LD A, C 127 | RET 128 | 129 | ; 130 | ; Send an ACK.. 131 | ; 132 | i2c_ack CALL i2c_sda_low 133 | CALL i2c_scl_cycle 134 | JR i2c_sda_high 135 | 136 | ; 137 | ; Send a byte in A, returning the ACK state in D 138 | ; Uses A, B, C, 139 | ; 140 | i2c_send_byte PUSH HL 141 | PUSH DE 142 | LD HL, (port_b_mode) ; L = port_b_mode, H = port_b_dir 143 | LD D, A 144 | 145 | LD A, ~(I2C_DATA_MASK|I2C_CLK_MASK) ; Set SDA and SCL (port_b_dir bit) LOW 146 | AND H 147 | SLA A 148 | LD H, A 149 | 150 | LD C, PIO_B_CTRL 151 | LD B, 8 152 | 153 | LD E, I2C_CLK_MASK 154 | 155 | _fast_loop LD A, H 156 | SLA D 157 | RR A 158 | OUT (C),L 159 | OUT (PIO_B_CTRL), A 160 | 161 | OR E 162 | OUT (C), L 163 | OUT (PIO_B_CTRL), A ; Clock high 164 | 165 | XOR E 166 | OUT (C), L 167 | OUT (PIO_B_CTRL),A ; Clock low 168 | DJNZ _fast_loop 169 | 170 | LD A, H 171 | SCF 172 | RR A 173 | OUT (C),L ; Release SDA 174 | OUT (PIO_B_CTRL), A 175 | 176 | OR E 177 | OUT (C), L 178 | OUT (PIO_B_CTRL), A ; Clock high 179 | 180 | OUT (C), L 181 | XOR E 182 | LD L, A 183 | LD (port_b_dir), A 184 | 185 | IN A, (PIO_B_DATA) ; Read ACK 186 | OUT (C),L ; Clock low 187 | 188 | POP DE 189 | POP HL 190 | LD D, A 191 | RET 192 | 193 | ; Cycle SCL, returning SDA,SCL in D 194 | ; 195 | ; Uses A, D 196 | i2c_scl_cycle2 CALL i2c_scl_low 197 | CALL i2c_scl_high 198 | IN A, (PIO_B_DATA) 199 | LD D, A 200 | ; Fall into scl_low... 201 | 202 | ; SCL/SDA toggle routines 203 | ; 204 | ; All use A 205 | i2c_scl_low LD A, (port_b_mode) 206 | OUT (PIO_B_CTRL), A 207 | 208 | LD A, (port_b_dir) 209 | RES I2C_CLK_BIT, A 210 | OUT (PIO_B_CTRL), A 211 | LD (port_b_dir), A 212 | RET 213 | 214 | i2c_sda_high LD A, (port_b_mode) 215 | OUT (PIO_B_CTRL), A 216 | 217 | LD A, (port_b_dir) 218 | SET I2C_DATA_BIT, A 219 | OUT (PIO_B_CTRL), A 220 | LD (port_b_dir), A 221 | RET 222 | 223 | i2c_sda_low LD A, (port_b_mode) 224 | OUT (PIO_B_CTRL), A 225 | 226 | LD A, (port_b_dir) 227 | RES I2C_DATA_BIT, A 228 | OUT (PIO_B_CTRL), A 229 | LD (port_b_dir), A 230 | RET 231 | 232 | i2c_scl_high LD A, (port_b_mode) 233 | OUT (PIO_B_CTRL), A 234 | 235 | LD A, (port_b_dir) 236 | SET I2C_CLK_BIT, A 237 | OUT (PIO_B_CTRL), A 238 | LD (port_b_dir), A 239 | RET 240 | 241 | i2c_scl_cycle PUSH BC 242 | LD BC, PIO_B_CTRL 243 | LD A, (port_b_mode) 244 | LD D, A 245 | LD A, (port_b_dir) 246 | 247 | RES I2C_CLK_BIT, A 248 | LD (port_b_dir), A 249 | OUT (C), D 250 | OUT (PIO_B_CTRL), A 251 | 252 | SET I2C_CLK_BIT, A 253 | OUT (C), D 254 | OUT (PIO_B_CTRL), A 255 | 256 | IN A, (PIO_B_DATA) 257 | OUT (C), D 258 | LD D, A 259 | LD A, (port_b_dir) 260 | OUT (PIO_B_CTRL), A 261 | POP BC 262 | RET 263 | 264 | .MODULE main 265 | -------------------------------------------------------------------------------- /src/examples/manicminer/README.md: -------------------------------------------------------------------------------- 1 | # ManicMiner Port for MicroBeast + VideoBeast 2 | 3 | Based on the Skoolkit disassembly (here: https://gitlab.com/z80-source-code-software/other-systems/manic-miner-disassembly---zx-spectrum/-/blob/master/mm.asm) 4 | 5 | Build with Pasmo: 6 | 7 | `pasmo mm.asm mm1_m4000.bin` 8 | 9 | ## Running 10 | 11 | Start MicroBeast BIOS, then use YModem file transfer to load to address `4000h` (Use `Address from file` option to 12 | load `mm1_m4000.bin` to the right location automatically). Or in BeastEm emulator, load the file directly to address 13 | `4000h` once the BIOS is running. 14 | 15 | When the file is loaded, execute from address 5400h. 16 | 17 | ## Explanation 18 | 19 | The original disassembly has been lightly altered to account for the different keyboard ports and higher processor speed 20 | of MicroBeast, and to provide a font (the original Spectrum version uses the Sinclair BASIC ROM font). The changes are 21 | made with equates, which allow the alterations to be switched off to generate code that would run normally on a 22 | Spectrum. 23 | 24 | In addition, setup routines are needed to configure MicroBeast and VideoBeast to have a similar memory map 25 | to a 48K Spectrum. Luckily, the original code for ManicMiner has a gap around address `9400h` which is large enough to 26 | include both the font and setup routines. 27 | 28 | Normally Manic Miner loads from address 32768 to 65535 (the top 32K of memory). To make it easier to load on MicroBeast, 29 | which executes its BIOS from the upper ~8K of RAM (where Manic Miner would normally store map data), the setup routines 30 | assume the 32kB file is loaded to a lower location (from address `4000h`), and then re-adjust the page layout to 31 | run the game from the normal address. 32 | -------------------------------------------------------------------------------- /src/examples/manicminer/carton.asm: -------------------------------------------------------------------------------- 1 | ; Carton font from https://damieng.com/zx-origins 2 | defb &00,&00,&00,&00,&00,&00,&00,&00 ; 3 | defb &10,&10,&10,&10,&10,&00,&10,&00 ; ! 4 | defb &24,&24,&48,&00,&00,&00,&00,&00 ; " 5 | defb &00,&24,&7e,&24,&24,&7e,&24,&00 ; # 6 | defb &08,&3e,&48,&3c,&12,&7c,&10,&00 ; $ 7 | defb &40,&a4,&48,&10,&24,&4a,&04,&00 ; % 8 | defb &30,&48,&40,&32,&4a,&44,&3a,&00 ; & 9 | defb &08,&08,&10,&00,&00,&00,&00,&00 ; ' 10 | defb &08,&10,&20,&20,&20,&10,&08,&00 ; ( 11 | defb &20,&10,&08,&08,&08,&10,&20,&00 ; ) 12 | defb &00,&10,&54,&38,&54,&10,&00,&00 ; * 13 | defb &00,&10,&10,&7c,&10,&10,&00,&00 ; + 14 | defb &00,&00,&00,&00,&00,&10,&10,&20 ; , 15 | defb &00,&00,&00,&7c,&00,&00,&00,&00 ; - 16 | defb &00,&00,&00,&00,&00,&10,&10,&00 ; . 17 | defb &02,&04,&08,&10,&20,&40,&80,&00 ; / 18 | defb &38,&44,&8a,&92,&a2,&44,&38,&00 ; 0 19 | defb &08,&18,&08,&08,&08,&08,&1c,&00 ; 1 20 | defb &3c,&42,&04,&08,&10,&20,&7e,&00 ; 2 21 | defb &7e,&04,&08,&1c,&02,&42,&3c,&00 ; 3 22 | defb &04,&0c,&14,&24,&44,&7e,&04,&00 ; 4 23 | defb &7e,&40,&7c,&02,&02,&42,&3c,&00 ; 5 24 | defb &08,&10,&20,&3c,&42,&42,&3c,&00 ; 6 25 | defb &7e,&02,&04,&08,&10,&10,&10,&00 ; 7 26 | defb &3c,&42,&42,&3c,&42,&42,&3c,&00 ; 8 27 | defb &3c,&42,&42,&3c,&04,&08,&10,&00 ; 9 28 | defb &00,&10,&10,&00,&00,&10,&10,&00 ; : 29 | defb &00,&10,&10,&00,&00,&10,&10,&20 ; ; 30 | defb &00,&0c,&30,&40,&30,&0c,&00,&00 ; < 31 | defb &00,&00,&7e,&00,&7e,&00,&00,&00 ; = 32 | defb &00,&30,&0c,&02,&0c,&30,&00,&00 ; > 33 | defb &3c,&42,&02,&0c,&10,&00,&10,&00 ; ? 34 | defb &38,&44,&9a,&aa,&bc,&40,&3c,&00 ; @ 35 | defb &10,&28,&28,&44,&7c,&44,&82,&00 ; A 36 | defb &7c,&42,&42,&7c,&42,&42,&7c,&00 ; B 37 | defb &3c,&42,&80,&80,&80,&42,&3c,&00 ; C 38 | defb &78,&44,&42,&42,&42,&44,&78,&00 ; D 39 | defb &7e,&40,&40,&78,&40,&40,&7e,&00 ; E 40 | defb &7e,&40,&40,&78,&40,&40,&40,&00 ; F 41 | defb &3c,&42,&80,&8e,&82,&46,&3a,&00 ; G 42 | defb &42,&42,&42,&7e,&42,&42,&42,&00 ; H 43 | defb &38,&10,&10,&10,&10,&10,&38,&00 ; I 44 | defb &02,&02,&02,&02,&42,&44,&38,&00 ; J 45 | defb &44,&48,&50,&60,&50,&48,&44,&00 ; K 46 | defb &40,&40,&40,&40,&40,&40,&7e,&00 ; L 47 | defb &c6,&c6,&aa,&aa,&92,&92,&82,&00 ; M 48 | defb &62,&62,&52,&52,&4a,&4a,&46,&00 ; N 49 | defb &38,&44,&82,&82,&82,&44,&38,&00 ; O 50 | defb &7c,&42,&42,&7c,&40,&40,&40,&00 ; P 51 | defb &38,&44,&82,&82,&8a,&44,&3a,&02 ; Q 52 | defb &7c,&42,&42,&7c,&48,&44,&42,&00 ; R 53 | defb &3c,&42,&40,&3c,&02,&42,&3c,&00 ; S 54 | defb &fe,&10,&10,&10,&10,&10,&10,&00 ; T 55 | defb &82,&82,&82,&82,&82,&44,&38,&00 ; U 56 | defb &82,&82,&44,&44,&28,&28,&10,&00 ; V 57 | defb &82,&82,&82,&54,&54,&28,&28,&00 ; W 58 | defb &82,&44,&28,&10,&28,&44,&82,&00 ; X 59 | defb &82,&82,&44,&28,&10,&10,&10,&00 ; Y 60 | defb &7e,&04,&08,&10,&20,&40,&7e,&00 ; Z 61 | defb &38,&20,&20,&20,&20,&20,&38,&00 ; [ 62 | defb &80,&40,&20,&10,&08,&04,&02,&00 ; \ 63 | defb &38,&08,&08,&08,&08,&08,&38,&00 ; ] 64 | defb &10,&28,&28,&44,&00,&00,&00,&00 ; ^ 65 | defb &00,&00,&00,&00,&00,&00,&00,&ff ; _ 66 | defb &1c,&22,&20,&7c,&20,&20,&7e,&00 ; £ 67 | defb &00,&00,&3c,&02,&3e,&42,&3e,&00 ; a 68 | defb &40,&40,&5c,&62,&42,&42,&7c,&00 ; b 69 | defb &00,&00,&3c,&42,&40,&40,&3e,&00 ; c 70 | defb &02,&02,&3a,&46,&42,&42,&3e,&00 ; d 71 | defb &00,&00,&3c,&42,&7e,&40,&3e,&00 ; e 72 | defb &0e,&10,&10,&7c,&10,&10,&10,&00 ; f 73 | defb &00,&00,&3e,&42,&42,&3e,&02,&3c ; g 74 | defb &40,&40,&5c,&62,&42,&42,&42,&00 ; h 75 | defb &10,&00,&30,&10,&10,&10,&18,&00 ; i 76 | defb &04,&00,&0c,&04,&04,&04,&44,&38 ; j 77 | defb &40,&40,&42,&4c,&70,&4c,&42,&00 ; k 78 | defb &30,&10,&10,&10,&10,&10,&18,&00 ; l 79 | defb &00,&00,&ec,&92,&92,&92,&92,&00 ; m 80 | defb &00,&00,&5c,&62,&42,&42,&42,&00 ; n 81 | defb &00,&00,&3c,&42,&42,&42,&3c,&00 ; o 82 | defb &00,&00,&7c,&42,&42,&7c,&40,&40 ; p 83 | defb &00,&00,&3e,&42,&42,&3e,&02,&02 ; q 84 | defb &00,&00,&5c,&62,&40,&40,&40,&00 ; r 85 | defb &00,&00,&3e,&40,&3c,&02,&7c,&00 ; s 86 | defb &10,&10,&7c,&10,&10,&10,&0e,&00 ; t 87 | defb &00,&00,&42,&42,&42,&46,&3a,&00 ; u 88 | defb &00,&00,&42,&42,&24,&24,&18,&00 ; v 89 | defb &00,&00,&82,&92,&aa,&44,&44,&00 ; w 90 | defb &00,&00,&42,&24,&18,&24,&42,&00 ; x 91 | defb &00,&00,&42,&42,&24,&18,&10,&60 ; y 92 | defb &00,&00,&7e,&04,&18,&20,&7e,&00 ; z 93 | defb &0e,&10,&10,&60,&10,&10,&0e,&00 ; { 94 | defb &10,&10,&10,&10,&10,&10,&10,&00 ; | 95 | defb &70,&08,&08,&06,&08,&08,&70,&00 ; } 96 | defb &00,&00,&62,&92,&8c,&00,&00,&00 ; ~ 97 | defb &3c,&42,&99,&a1,&a1,&99,&42,&3c ; © 98 | -------------------------------------------------------------------------------- /src/examples/manicminer/microbeast.asm: -------------------------------------------------------------------------------- 1 | ; Setup routines for ManicMiner on MicroBeast 2 | ; 3 | ; Initialises the memory map and configures VideoBeast to emulate a Sinclair screen. 4 | ; 5 | 6 | INCLUDE "microbeast.inc" 7 | 8 | DI ; Relocate the pages.. 9 | LD A, 021h 10 | OUT (IO_PAGE_2), A 11 | INC A 12 | OUT (IO_PAGE_3), A 13 | JP microbeast_init 14 | 15 | microbeast_init LD A, VIDEOBEAST_PAGE ; VideoBeast in Bank 1 (4000h-7fffh) 16 | OUT (IO_PAGE_1), A 17 | 18 | LD A, VB_UNLOCK ; Unlock registers 19 | LD (VB_REGISTERS_LOCKED), A 20 | 21 | LD A, MODE_640 | MODE_DOUBLE | MODE_MAP_16K 22 | LD (VB_MODE), A 23 | 24 | LD A, 0 25 | LD (VB_PAGE_0), A 26 | 27 | LD HL, VB_LAYER_0 ; Disable all layers 28 | LD DE, 16 29 | LD B, 6 30 | 31 | clear_layers LD (HL), A 32 | ADD HL, DE 33 | DJNZ clear_layers 34 | 35 | LD A, 1 ; Palette 4-7 in bottom half of registers 36 | LD (VB_LOWER_REGS), A 37 | 38 | LD HL, sinclair_pal ; Copy our sinclair colours into palette 7 39 | LD DE, VB_REGISTERS + 32*3 40 | LD BC, 32 41 | LDIR 42 | 43 | LD HL, sinclair_layer ; Then set up the top layer as our display 44 | LD DE, VB_LAYER_5 45 | LD BC, 16 46 | LDIR 47 | 48 | LD HL, 38FFh ; Now clear it ready for a high-res bitmap 49 | LD (VBASE), HL 50 | 51 | LD HL, VBASE 52 | LD DE, VBASE+2 53 | LD BC, 8192 54 | LDIR 55 | 56 | ; Set up the VideoBeast memory map to emulate a Sinclair layout. 57 | LD A, MODE_640 | MODE_DOUBLE | MODE_MAP_SINCLAIR 58 | LD (VB_MODE), A 59 | LD A, 0ch 60 | LD (VB_PAGE_1), A ; Bitmap base 61 | LD A, 0 62 | LD (VB_PAGE_2), A ; Screen offsets 63 | LD A, 1 64 | LD (VB_PAGE_3), A ; Rest of 16K 65 | 66 | LD HL, VBASE ; Now clear the screen 67 | LD DE, VBASE+1 68 | LD BC, 6143 69 | LD (HL), 0 70 | LDIR 71 | 72 | XOR A ; And lock the registers 73 | LD (VB_REGISTERS_LOCKED), A 74 | 75 | JP BEGIN 76 | 77 | beast_layer DB TYPE_BITMAP_4, 4, 4+16-2, 4, 4+32, 0A8h, 0, 068h 78 | DB 010h ; Bitmap in page 10h 79 | DB 0h ; 80 | DB 01h ; Palette 1 81 | DB 0 ; 82 | DB 0, 0, 0, 0 83 | 84 | sinclair_layer DB TYPE_TEXT, 4, 4+24-2, 4, 4+32, 0, 0, 0 85 | DB 0 ; Character map at offset 0 86 | DB 010h ; Font at 16 * 2k -> 32kb 87 | DB 017h ; Palette 7, Sinclair layout 88 | DB 0ch ; Bitmap at 12 * 16k -> 192Kb 89 | DB 0, 0, 0, 0 90 | 91 | ; Sinclair palette (black, blue, red, magenta, green, cyan, yellow, white) 92 | sinclair_pal DW 00000h, 00018h, 06000h, 06018h, 00300h, 00318h, 06300h, 06318h ; Normal 93 | DW 00000h, 0001Ch, 07000h, 0701Ch, 00380h, 0039Ch, 07380h, 0739Ch ; Bright 94 | -------------------------------------------------------------------------------- /src/examples/manicminer/microbeast.inc: -------------------------------------------------------------------------------- 1 | VBASE EQU 04000h ; Assume VideoBeast is paged into Bank 1 (ie. 4000h - 7FFFh) 2 | 3 | VB_MODE EQU VBASE + 03FFFh ; VideoBeast register offsets 4 | VB_REGISTERS_LOCKED EQU VBASE + 03FFEh 5 | 6 | VB_PAGE_0 EQU VBASE + 03FF9h 7 | VB_PAGE_1 EQU VBASE + 03FF8h 8 | VB_PAGE_2 EQU VBASE + 03FF7h 9 | VB_PAGE_3 EQU VBASE + 03FF6h 10 | 11 | VB_LOWER_REGS EQU VBASE + 03FF5h 12 | 13 | VB_LAYER_0 EQU VBASE + 03F80h 14 | VB_LAYER_1 EQU VBASE + 03F90h 15 | VB_LAYER_2 EQU VBASE + 03FA0h 16 | VB_LAYER_3 EQU VBASE + 03FB0h 17 | VB_LAYER_4 EQU VBASE + 03FC0h 18 | VB_LAYER_5 EQU VBASE + 03FD0h 19 | 20 | VB_REGISTERS EQU VBASE + 03F00h 21 | 22 | MODE_640 EQU 0 23 | MODE_848 EQU 1 24 | MODE_DOUBLE EQU 8 25 | MODE_TESTCARD EQU 010h 26 | 27 | MODE_MAP_16K EQU 0 28 | MODE_MAP_SINCLAIR EQU 080h 29 | 30 | LAYER_TYPE EQU 0 31 | LAYER_TOP EQU 1 32 | LAYER_BOTTOM EQU 2 33 | LAYER_LEFT EQU 3 34 | LAYER_RIGHT EQU 4 35 | LAYER_SCROLL_X EQU 5 36 | LAYER_SCROLL_XY EQU 6 37 | LAYER_SCROLL_Y EQU 7 38 | 39 | TYPE_NONE EQU 0 40 | TYPE_TEXT EQU 1 41 | TYPE_SPRITE EQU 2 42 | TYPE_TILE EQU 3 43 | TYPE_BITMAP_8 EQU 4 44 | TYPE_BITMAP_4 EQU 5 45 | 46 | TEXT_MAP_BASE EQU 8 ; 16Kb character map 47 | TEXT_FONT_BASE EQU 9 ; 2Kb font offset 48 | TEXT_PALETTE EQU 10 ; Bits 0-3: Palette number Bit 4: Use Sinclair bit pattern 49 | TEXT_BITMAP EQU 11 ; 16Kb 1bpp bitmap.. 50 | 51 | VB_UNLOCK EQU 0F3h ; Unlock register write 52 | 53 | BIOS_SET_PAGE EQU 0fde2h ; Call with A -> which bank to map 0-3, and E -> Which physical page to map to 00-1F => ROM, 20-3F => RAM, 40 => VIDEOBEAST 54 | 55 | VIDEOBEAST_PAGE EQU 40h 56 | 57 | IO_PAGE_0 EQU 070h ; MicroBeast page mapping ports. 58 | IO_PAGE_1 EQU 071h 59 | IO_PAGE_2 EQU 072h 60 | IO_PAGE_3 EQU 073h 61 | -------------------------------------------------------------------------------- /src/examples/ports.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; Port definintions 3 | ; 4 | ; 5 | 6 | CARRIAGE_RETURN .EQU 0Dh 7 | NEWLINE .EQU 0Ah 8 | 9 | ;=================================== UART ============================================ 10 | UART_TX_RX .EQU 020h ; Read: receiver buffer, Write: transmitter buffer 11 | UART_INT_ENABLE .EQU 021h ; Interrupt enable register 12 | UART_INT_ID .EQU 022h ; Read: Interrupt identification register 13 | UART_FIFO_CTRL .EQU 022h ; Write: FIFO Control register 14 | UART_LINE_CTRL .EQU 023h ; Line control register 15 | UART_MODEM_CTRL .EQU 024h ; Modem control 16 | UART_LINE_STATUS .EQU 025h ; Line status 17 | UART_MODEM_STATUS .EQU 026h ; Modem status 18 | UART_SCRATCH .EQU 027h ; Scratch register 19 | 20 | ;==================================== PIO ============================================ 21 | PIO_A_DATA .EQU 010h 22 | PIO_A_CTRL .EQU 012h 23 | 24 | PIO_B_DATA .EQU 011h 25 | PIO_B_CTRL .EQU 013h 26 | 27 | PIO_MODE_0 .EQU 00Fh ; Mode 0: All outputs 28 | PIO_MODE_1 .EQU 04fh ; Mode 1: All inputs 29 | PIO_MODE_2 .EQU 080h ; Mode 2 (Port A only): Bi-directional 30 | PIO_MODE_3 .EQU 0CFh ; Mode 3: Per-pin I/O on the given port - write an additional word with bits set (1) for input, reset (0) for output on the matching pin. 31 | 32 | PIO_SET_INTERRUPT .EQU 007h ; Set interrupt control world. By itself, this wil disable interrupts on the given port. OR with the following constants to change this 33 | PIO_ENABLE_INT .EQU 080h ; Enable interrupts on the given port, when OR'd with the PIO_SET_INTERRUPT control word. 34 | PIO_INT_MASK .EQU 010h ; When OR'd with the PIO_SET_INTERRUPT control word, the following word will enable interrupts for pins where the matching bit is zero 35 | 36 | ;================================== AUDIO ============================================ 37 | ; Constants for Audio output 38 | AUDIO_PIO .EQU 1 ; Audio on PIO (rev. 0.1 boards) 39 | AUDIO_UART .EQU 2 ; Audio on UART (rev. 0.2 boards) 40 | 41 | AUDIO_VERSION .EQU AUDIO_UART 42 | 43 | #IF AUDIO_VERSION = AUDIO_PIO 44 | PORT_B_IOMASK .EQU 0EFh ; All inputs, apart from bit 4 (audio out) 45 | AUDIO_MASK .EQU 010h ; Bitmask for audio output on Port B. The bit is set for the output pin. 46 | AUDIO_PORT .EQU PIO_B_DATA 47 | 48 | #ELSE 49 | PORT_B_IOMASK .EQU 0FFh ; All inputs 50 | AUDIO_MASK .EQU 008h ; Bitmask for audio output on UART Out 2. The bit is set for the output pin 51 | AUDIO_PORT .EQU UART_MODEM_CTRL 52 | 53 | #ENDIF 54 | 55 | 56 | ;=================================== MEMORY PAGING =================================== 57 | IO_MEM_0 .EQU 070h ; Page 0: 0000h - 3fffh 58 | IO_MEM_1 .EQU 071h ; Page 1: 4000h - 7fffh 59 | IO_MEM_2 .EQU 072h ; Page 2: 8000h - bfffh 60 | IO_MEM_3 .EQU 073h ; Page 3: c000h - ffffh 61 | 62 | IO_MEM_CTRL .EQU 074h ; Paging enable register 63 | IO_MEM_ENABLE .EQU 1 64 | IO_MEM_DISABLE .EQU 0 65 | 66 | 67 | ;====================================== I2C DEVICES =================================== 68 | I2C_DATA_BIT .equ 7 69 | I2C_CLK_BIT .equ 6 70 | 71 | I2C_DATA_MASK .equ 1 << I2C_DATA_BIT 72 | I2C_CLK_MASK .equ 1 << I2C_CLK_BIT 73 | 74 | ; Display 75 | ;========== 76 | DL_ADDRESS .EQU 050h ; Left Matrix controller I2C address 77 | DR_ADDRESS .EQU 053h ; Right Matrix controller I2C address 78 | 79 | DISP_REG_CRWL .EQU 0FEh ; Command Register write lock 80 | DISP_UNLOCK .EQU 0C5h ; Unlock command 81 | 82 | DISP_DEFAULT_BRIGHTNESS .EQU 080h ; Default brightness 83 | DISP_DIMMED .EQU 018h ; Dimmed 84 | 85 | ; RTC 86 | ;========== 87 | RTC_ADDRESS .EQU 06fh 88 | 89 | RTC_REG_SEC .EQU 000h ; Also has oscillator enable bit in B7, 1 = run 90 | RTC_REG_MIN .EQU 001h 91 | RTC_REG_HOUR .EQU 002h ; B6: 1 = 12hr/ 0 = 24hr clock (r/w) 92 | ; If 12 hr clock, B5: 1 = PM/ 0 = AM. B4: hour tens. Otherwise B5-4: hour tens, B3-0: hour units 93 | RTC_REG_WKDAY .EQU 003h ; Oscillator status bit in B5, 1 = enabled and running. 94 | ; B4: 1 = power was lost, write 0 to clear (timestamp registers are set) 95 | ; B3: 1 = enable external battery supply (VBAT) 96 | ; B2-0: Weekday, from 1 to 7 97 | RTC_REG_DATE .EQU 004h ; BCD Date (1 to 31) 98 | RTC_REG_MTH .EQU 005h ; B5: 1 = Leap year (read only). B4: month tens, B3-0: month units (Month is 1 to 12) 99 | RTC_REG_YEAR .EQU 006h ; BCD Year 100 | 101 | RTC_REG_CTRL .EQU 007h ; B7: If Square wave and Alarm 0 and Alarm 1 are disabled, sets Output Pin level 102 | ; B6: SQWEN, 1 = Enable square wave on Output Pin, Alarms disabled 103 | ; B5, B4: Alarm 1, 0 Enable. 1 = Alarm is enabled 104 | ; B3: 1 = Use external oscillator 105 | ; B2: CRSTRIM, 1 = Coarse trim mode, Output pin is 64Hz 106 | ; B1-0: If SQWEN = 1 & CRSTRIM = 0, sets Output pin freq. 00 -> 1Hz, 01 -> 4.096kHz, 10 -> 8.192kHz, 11 -> 32.768kHz 107 | RTC_REG_TRIM .EQU 008h ; Trim, initially 0. B7: Sign, 1=Add, 0=Subtract clock cycles. 108 | ; B6-0: Trim amount/2. Applied 1 every minute in fine trim, 128 times a second in coarse trim mode. 0 = disable trim 109 | -------------------------------------------------------------------------------- /src/examples/snes.asm: -------------------------------------------------------------------------------- 1 | ; snes.asm - A simple demonstration to read a SNES controller through the MicroBeast GPIO 2 | ; 3 | ; Uses the base BIOS to write the buttons being pressed to the display. 4 | ; 5 | ; Build with: 6 | ; tasm -t80 -b mandel.asm mandel_m8000.bin 7 | ; 8 | ; 9 | ; Assumes the following connections on the GPIO header: 10 | ; 11 | ; GPIO SNES 12 | ; _______ 13 | ; (A) (A) +5v --------- +5v | (1) | 14 | ; (B) (C) PB0 -------> Clock | (2) | 15 | ; (D) (E) PB1 -------> Latch | (3) | 16 | ; (F) (G) PB2 <------- Data | (4) | 17 | ; (H) (I) PB3 |-----| 18 | ; (J) (K) BRDY | (5) | 19 | ; (L) (M) ARDY | (6) | 20 | ; (N) (O) ~BSTB +-- GND | (7) | 21 | ; (P) (Q) ~ASTB | \_____/ 22 | ; (R) (R) GND -------+ 23 | ; 24 | 25 | .MODULE main 26 | 27 | .ORG 08000h 28 | 29 | CALL setup_snes 30 | 31 | _snes_loop LD BC,0FD00h ; A9 is low -> Read Row 1 32 | IN A, (C) ; A contains keys G, F, D, S, A, CTRL 33 | AND 03Fh 34 | CP 03Fh 35 | RET NZ ; Return if a key is pressed 36 | 37 | CALL read_snes 38 | LD A, (_last_value) 39 | CP L 40 | JR NZ, _changed 41 | LD A, (_last_value+1) 42 | CP H 43 | JR Z, _delay 44 | 45 | _changed LD (_last_value), HL 46 | 47 | LD DE, _message 48 | CALL _write_string 49 | 50 | LD HL, (_last_value) 51 | LD DE, _snes_btns 52 | LD B, 12 53 | 54 | _output_loop PUSH DE 55 | PUSH BC 56 | SLA L 57 | RL H 58 | PUSH HL 59 | 60 | LD C, 9 61 | CALL NC, _write_string 62 | 63 | POP HL 64 | POP BC 65 | POP DE 66 | _next LD A, (DE) 67 | INC DE 68 | CP '$' 69 | JR NZ, _next 70 | DJNZ _output_loop 71 | 72 | _delay 73 | LD BC, 0 74 | _delay_loop DEC BC 75 | LD A, B 76 | OR C 77 | JR NZ, _delay_loop 78 | JR _snes_loop 79 | 80 | _message .DB CARRIAGE_RETURN, ESCAPE_CHAR, 'K', "Pressed $" 81 | 82 | _snes_btns .DB "B $" 83 | .DB "Y $" 84 | .DB "Select $" 85 | .DB "Start $" 86 | .DB "Up $" 87 | .DB "Down $" 88 | .DB "Left $" 89 | .DB "Right $" 90 | .DB "A $" 91 | .DB "X $" 92 | .DB "L $" 93 | .DB "R $$$" 94 | 95 | _write_string LD A, (DE) 96 | CP '$' 97 | RET Z 98 | LD C, A 99 | PUSH DE 100 | CALL BIOS_CONOUT 101 | POP DE 102 | INC DE 103 | JR _write_string 104 | 105 | _last_value .DW 0 106 | 107 | ; 108 | ; Setup the PIO to read the SNES controller. 109 | ; 110 | setup_snes DI 111 | LD A, PIO_MODE_3 ; Port B mode 3 112 | OUT (PIO_B_CTRL), A 113 | LD A, PORT_B_IOMASK ; All inputs, apart from bits 1 (Latch) and 0 (Clock) 114 | LD (port_b_dir), A ; Stop BIOS from messing it up 115 | OUT (PIO_B_CTRL), A 116 | 117 | LD A, SNES_IDLE 118 | LD (port_b_data), A 119 | OUT (PIO_B_DATA), A 120 | EI 121 | RET 122 | 123 | ; 124 | ; Read the SNES controller, returning the bitmask in HL 125 | ; 126 | ; 127 | 128 | read_snes DI 129 | LD HL, 01 130 | LD C, PIO_B_DATA 131 | 132 | LD E, SNES_IDLE | SNES_LATCH 133 | OUT (C), E 134 | 135 | LD B, 10 136 | DJNZ $ 137 | LD E, SNES_IDLE 138 | OUT (C), E 139 | 140 | _read_loop LD B, 8 141 | DJNZ $ 142 | 143 | IN A, (C) 144 | RRA 145 | RRA 146 | AND 01 147 | 148 | SLA L 149 | RL H 150 | JR C, _read_done 151 | 152 | OR L 153 | LD L, A 154 | 155 | LD E, 0 156 | OUT (C), E 157 | 158 | LD B, 10 159 | DJNZ $ 160 | 161 | LD E, SNES_IDLE 162 | OUT (C), E 163 | 164 | JR _read_loop 165 | 166 | _read_done EI 167 | RET 168 | 169 | ; Used by BIOS to manage I2C connection on high bits of Port B 170 | ; 171 | port_b_dir .EQU 0FF01h 172 | port_b_data .EQU 0FF02h 173 | 174 | 175 | ; Location of BIOS conout routine 176 | ; 177 | BIOS_CONOUT .EQU 0EE0Ch 178 | 179 | 180 | ; 181 | ; General constants 182 | ; 183 | 184 | CARRIAGE_RETURN .EQU 0Dh 185 | NEWLINE .EQU 0Ah 186 | ESCAPE_CHAR .EQU 1Bh 187 | 188 | SNES_CLOCK .EQU 001h 189 | SNES_LATCH .EQU 002h 190 | 191 | SNES_IDLE .EQU SNES_CLOCK 192 | 193 | 194 | PIO_B_DATA .EQU 011h 195 | PIO_B_CTRL .EQU 013h 196 | 197 | PIO_MODE_0 .EQU 00Fh ; Mode 0: All outputs 198 | PIO_MODE_1 .EQU 04fh ; Mode 1: All inputs 199 | PIO_MODE_2 .EQU 080h ; Mode 2 (Port A only): Bi-directional 200 | PIO_MODE_3 .EQU 0CFh ; Mode 3: Per-pin I/O on the given port - write an additional word with bits set (1) for input, reset (0) for output on the matching pin. 201 | 202 | PORT_B_IOMASK .EQU 0FCh ; All inputs, apart from bits 1 (Latch) and 0 (Clock) 203 | 204 | 205 | .END 206 | -------------------------------------------------------------------------------- /src/examples/uart.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; UART routines.. 3 | ; 4 | ; 5 | 6 | .MODULE uart 7 | 8 | ; 9 | ; Baud rates, assuming 1.8432Mhz crystal 10 | ; 11 | UART_9600 .EQU 12 12 | UART_19200 .EQU 6 13 | UART_38400 .EQU 3 14 | 15 | UART_MODE_AUTO .EQU 022h ; Auto flow mode 16 | UART_MODE_NO_FLOW .EQU 000h ; Auto RTS and CTS disabled 17 | UART_MODE_DIAG .EQU 030h ; Loopback mode 18 | 19 | ; 20 | ; Various constants 21 | ; 22 | UART_8N1 .EQU 003h 23 | UART_TIMEOUT .EQU 50000 24 | 25 | _CTS_STATUS_MASK .EQU 010h 26 | 27 | ; 28 | ; Set up the UART. Assume it has had time to settle after reset... 29 | ; 30 | ; 31 | uart_init LD BC, UART_19200 ; B is flow control, 0 -> No auto flow control 32 | 33 | IN A,(UART_MODEM_STATUS) ; If CTS is enabled, assume we can use flow control 34 | AND _CTS_STATUS_MASK 35 | JR Z, _no_listener 36 | 37 | LD B, UART_MODE_AUTO 38 | 39 | _no_listener LD A, 80h ; Divisor Latch Setting Mode 40 | OUT (UART_LINE_CTRL), A ; - entered by writing 1 to bit 7 of LCR 41 | NOP 42 | NOP 43 | LD A, C 44 | OUT (UART_TX_RX), A 45 | NOP 46 | NOP 47 | XOR A 48 | OUT (UART_INT_ENABLE), A 49 | NOP 50 | NOP 51 | 52 | LD A, UART_8N1 ; Set 8N1 and exit divisor latch setting mode 53 | OUT (UART_LINE_CTRL), A 54 | 55 | LD A, 07h ; Enable and clear FIFO registers 56 | OUT (UART_FIFO_CTRL), A 57 | 58 | LD A, B 59 | AND A 60 | JR Z, _no_flowcontrol 61 | 62 | OUT (UART_MODEM_CTRL), A 63 | 64 | _no_flowcontrol NOP 65 | NOP 66 | RET 67 | 68 | ; 69 | ; Send character in A to UART 70 | ; Preserves all registers 71 | ; 72 | ; Carry flag is set on return if the UART send succeeded, clear if it timed out 73 | ; 74 | uart_send PUSH BC 75 | PUSH AF 76 | LD BC, UART_TIMEOUT 77 | _check_ready IN A, (UART_LINE_STATUS) 78 | BIT 5, A 79 | JP NZ, _uart_ready ; Bit 5 is set when the UART is ready 80 | DEC BC 81 | LD A, B 82 | OR C 83 | JP NZ, _check_ready 84 | 85 | POP AF 86 | POP BC 87 | SCF 88 | CCF 89 | RET 90 | 91 | _uart_ready POP AF 92 | POP BC 93 | OUT (UART_TX_RX), A 94 | SCF 95 | RET 96 | 97 | ; 98 | ; Check to see if there are any characters to receive 99 | ; Preserves all registers 100 | ; 101 | ; Returns with carry set if there are characters ready, clear if not 102 | ; 103 | uart_ready PUSH AF 104 | IN A, (UART_LINE_STATUS) 105 | BIT 0, A 106 | JP Z, _not_ready 107 | POP AF 108 | SCF 109 | RET 110 | 111 | _not_ready POP AF 112 | SCF 113 | CCF 114 | RET 115 | 116 | ; 117 | ; Receive a character from the UART in A 118 | ; 119 | ; Returns with a character in A and the carry flag set. If no characters 120 | ; are available, returns with the carry flag clear. 121 | ; 122 | uart_receive IN A, (UART_LINE_STATUS) 123 | BIT 0, A 124 | JP Z, _no_character 125 | IN A, (UART_TX_RX) 126 | SCF 127 | RET 128 | 129 | _no_character SCF 130 | CCF 131 | RET 132 | 133 | ; 134 | ; Write A as a hex byte 135 | ; Overwrites A... 136 | ; 137 | uart_hex PUSH AF 138 | SRA A 139 | SRA A 140 | SRA A 141 | SRA A 142 | CALL to_hex 143 | CALL uart_send 144 | POP AF 145 | CALL to_hex 146 | JP uart_send 147 | ; 148 | ; Returns the low nibble of A as a hex digit 149 | ; 150 | to_hex AND $0F ;LOW NIBBLE ONLY 151 | ADD A,$90 152 | DAA 153 | ADC A,$40 154 | DAA 155 | RET 156 | ; 157 | ; Inline send. Sends the zero terminated string immediately following the call to this function to the UART. 158 | ; e.g. CALL uart_inline 159 | ; .DB "My text to send", 0 160 | ; 161 | ; Returns with Carry set if the string was successfully sent, otherwise, carry is clear. 162 | ; 163 | ; Uses A 164 | ; 165 | uart_inline EX (SP), HL 166 | CALL uart_string 167 | JP C, _inline_end 168 | _find_end LD A, (HL) ; Get the current character (Carry preserved) 169 | INC HL ; Point to next character (Carry preserved) 170 | AND A ; Test if the current character was zero (Clears carry) 171 | JP NZ, _find_end ; If it was, we're done, otherwise repeat 172 | _inline_end EX (SP), HL 173 | RET 174 | ; 175 | ; Send a zero terminated string pointed to by HL to the UART 176 | ; 177 | ; Returns with Carry Set if the string was sent sucessfully, clear otherwise 178 | ; 179 | uart_string LD A,(HL) 180 | INC HL 181 | AND A 182 | JP Z, _string_end 183 | CALL uart_send 184 | JP C, uart_string 185 | RET 186 | _string_end SCF 187 | RET 188 | 189 | .MODULE main 190 | -------------------------------------------------------------------------------- /src/examples/videobeast/mandelbrot_benchmark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atoone/MicroBeast/4c5a9fdd1e71aa5e0d928267e6e1ae4ae0d5ae87/src/examples/videobeast/mandelbrot_benchmark.png --------------------------------------------------------------------------------