├── z80 ├── test_programs_asm │ ├── palette_all.rgb565 │ ├── plasma_pixels_80_60.raw │ ├── cls.z │ ├── plasma.z │ └── ls.z ├── multithread_test │ ├── threadded_entry.z │ └── kernel.c ├── z80int.z ├── z80os.z └── z80listfiles.z ├── README.md └── Teensy31 └── z80controller.ino /z80/test_programs_asm/palette_all.rgb565: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Domipheus/TeensyZ80/HEAD/z80/test_programs_asm/palette_all.rgb565 -------------------------------------------------------------------------------- /z80/test_programs_asm/plasma_pixels_80_60.raw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Domipheus/TeensyZ80/HEAD/z80/test_programs_asm/plasma_pixels_80_60.raw -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TeensyZ80 2 | Code and related parts of the TeensyZ80 project. 3 | 4 | This repo is in flux and will be populated with more code when it's ready! 5 | -------------------------------------------------------------------------------- /z80/test_programs_asm/cls.z: -------------------------------------------------------------------------------- 1 | ; 2 | ; TeensyZ80 clear screen 3 | 4 | 5 | PORT_DISP_CLEAR equ 20 6 | 7 | 8 | .org 01000h 9 | start: 10 | ld a,0 11 | out ($04), a 12 | ld a, 0 13 | out ($05), a 14 | out (PORT_DISP_CLEAR), a 15 | ret 16 | end -------------------------------------------------------------------------------- /z80/multithread_test/threadded_entry.z: -------------------------------------------------------------------------------- 1 | ; 2 | ; TeensyZ80 bootloader to multithreadded kernel.bin 3 | ; This needs to be assembled and bin2h'd into the 4 | ; Teensy Z80 sketch controller 5 | 6 | .org 0000h 7 | start: 8 | di 9 | ld sp, stack_kernel_top 10 | im 2 11 | ld a, 01h 12 | ld i, a 13 | jp kernel 14 | 15 | .org 0100h 16 | vectors: 17 | dc 256, 0 18 | 19 | .org 0200h 20 | thread_data: 21 | 22 | .org 0300h 23 | stack_1_bottom: 24 | 25 | .org 0400h 26 | stack_1_top: 27 | 28 | .org 0500h 29 | stack_2_top: 30 | 31 | .org 0600h 32 | stack_3_top: 33 | 34 | .org 0700h 35 | stack_4_top: 36 | 37 | .org 07F0h 38 | stack_kernel_top; 39 | 40 | .org 0800h 41 | kernel: 42 | ld a, 0 43 | out (04h), a 44 | out (05h), a 45 | ld a, '?' 46 | out (03h), a 47 | halt 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /z80/test_programs_asm/plasma.z: -------------------------------------------------------------------------------- 1 | ; 2 | ; TeensyZ80 display mode test 3 | 4 | PORT_RAM_BANK_SET equ 200 5 | PORT_RAM_BANK_RESET equ 07fffh 6 | PORT_VRAM_PALETTE_IDX equ 7 7 | PORT_VRAM_BUFFER_LOC equ 0 8 | PORT_VRAM_DRAW equ 8 9 | PORT_VRAM_SETMODE equ 9 10 | 11 | PORT_FILESYS_READ_WRITE equ 10 12 | PORT_FILESYS_OPEN_CLOSE equ 11 13 | PORT_FILESYS_NEXT equ 12 14 | 15 | FILESYS_RW_EXEC equ 13 16 | FILESYS_RW_SETCMDMEMPTR equ 2 17 | FILESYS_OPEN_OPENFILE equ 5 18 | FILESYS_OPEN_SETMEMPTR equ 6 19 | FILESYS_NEXT_GETNEXT equ 9 20 | FILESYS_NEXT_SETMEMPTR equ 10 21 | FILESYS_CLOSE_FILE equ 12 22 | 23 | OPEN_READ equ 0 24 | OPEN_WRITE equ 1 25 | OPEN_WRITE_CREATE equ 2 26 | OPEN_APPEND equ 3 27 | OPEN_RDWR equ 4 28 | 29 | COLOUR_BLACK equ 00000h 30 | COLOUR_BLUE equ 0001Fh 31 | COLOUR_RED equ 0F800h 32 | COLOUR_GREEN equ 007E0h 33 | COLOUR_CYAN equ 007FFh 34 | COLOUR_MAGENTA equ 0F81Fh 35 | COLOUR_YELLOW equ 0FFE0h 36 | COLOUR_WHITE equ 0FFFFh 37 | 38 | 39 | 40 | ;programs start at 0x1000 41 | .org 01000h 42 | start: 43 | ld de, str_console_prompt 44 | call print_string 45 | call newline 46 | 47 | ld a, 6 48 | out (PORT_VRAM_SETMODE), a ; 'vram' displaymode 6: 80x60 49 | 50 | ; we can put out BC now to write VRAM 51 | ld bc, 0200h ; pixel mem offset, after palette 52 | ld hl, 012c0h ; size of pixel data (80x60) 53 | ld de, image_pixels_80x60 ; pixel data in binary 54 | call ram_2_vram 55 | 56 | ld bc, 0 57 | loadpalette: 58 | inc bc 59 | inc bc 60 | ld de, palette_defn 61 | call palette_ram_2_vram 62 | 63 | ld hl, 0 64 | cycle_palette_idx: 65 | inc hl 66 | ld a, l 67 | cp 128 68 | jr z,exit_program 69 | out (PORT_VRAM_PALETTE_IDX), a ; inc palette idx 70 | ld a, 0 71 | out (PORT_VRAM_DRAW), a ; draw vram 72 | jr cycle_palette_idx 73 | 74 | exit_program: 75 | ret 76 | 77 | iloop: 78 | jr iloop 79 | 80 | 81 | print_string: 82 | push af 83 | push de 84 | print_string_loop: 85 | ld a, (de) 86 | or a 87 | jr z, print_string_end 88 | out ($03), a 89 | inc de 90 | jr print_string_loop 91 | print_string_end: 92 | pop de 93 | pop af 94 | ret 95 | 96 | newline: 97 | push af 98 | in a, ($04) 99 | inc a 100 | out ($04), a 101 | ld a, 0 102 | out ($05), a 103 | pop af 104 | ret 105 | 106 | setcolour: ;16-bit colour in bc 107 | push af 108 | ld a, b 109 | out ($06), a 110 | ld a, c 111 | out ($06), a 112 | pop af 113 | ret 114 | 115 | ; de = src palette in ram, bc = index start 116 | palette_ram_2_vram: 117 | di 118 | push de 119 | push bc 120 | push hl 121 | push af 122 | ld a, 1 123 | out (PORT_RAM_BANK_SET), a 124 | 125 | ;ld bc, 0 126 | ld hl, 0200h 127 | 128 | palette_ram_2_vram_loop: 129 | ld a, (de) 130 | out (c), a 131 | dec hl 132 | inc de 133 | inc bc 134 | 135 | ld a, b ;wrap 136 | and 01h 137 | ld b, a 138 | 139 | ld a, h 140 | or l 141 | jr nz,palette_ram_2_vram_loop 142 | 143 | ; return to non-vram 144 | ld bc, 0FFFFh 145 | in a, (c) 146 | pop af 147 | pop hl 148 | pop bc 149 | pop de 150 | ei 151 | ret 152 | 153 | 154 | ; de = src in ram, bc vram offset, hl = size 155 | ram_2_vram: 156 | di 157 | push de 158 | push bc 159 | push hl 160 | push af 161 | ld a, 1 162 | out (PORT_RAM_BANK_SET), a 163 | 164 | ram_2_vram_loop: 165 | ld a, (de) 166 | out (c), a 167 | dec hl 168 | inc de 169 | inc bc 170 | 171 | ld a, h 172 | or l 173 | jr nz,ram_2_vram_loop 174 | 175 | ; return to non-vram 176 | ld bc, 0FFFFh 177 | in a, (c) 178 | pop af 179 | pop hl 180 | pop bc 181 | pop de 182 | ei 183 | ret 184 | 185 | str_console_prompt: 186 | defb 'Loading plasma data into VRAM...',0 187 | 188 | image_pixels_80x60: 189 | incbin "plasma_pixels_80_60.raw" 190 | 191 | palette_defn: 192 | incbin "palette_all.rgb565" 193 | 194 | scratch_mem: 195 | 196 | end -------------------------------------------------------------------------------- /z80/z80int.z: -------------------------------------------------------------------------------- 1 | ; 2 | ; TeensyZ80 Mode 2 Interrupt test 3 | ; Prints a prompt to console, then infinitely halts. 4 | ; The timer interrupt prints a '.' every second. 5 | ; 6 | 7 | .org 0000h 8 | start: 9 | di 10 | ld sp, 3fffh 11 | im 2 12 | ld a, 01h 13 | ld I, a 14 | ld de, str_console_prompt 15 | call print_string 16 | ei 17 | 18 | iloop: 19 | halt 20 | jr iloop 21 | 22 | 23 | print_string: 24 | push af 25 | print_string_loop: 26 | ld a, (de) 27 | or a 28 | jr z, print_string_end 29 | out ($03), a 30 | inc de 31 | jr print_string_loop 32 | print_string_end: 33 | pop af 34 | ret 35 | 36 | ihdlr_unknown: 37 | di 38 | push de 39 | ld de, str_unknownint 40 | call print_string 41 | pop de 42 | ei 43 | reti 44 | 45 | ihdlr_second_timer: 46 | di 47 | push af 48 | ld a, 02eh ;print period to console 49 | out ($03), a 50 | pop af 51 | ei 52 | reti 53 | 54 | str_unknownint: 55 | defb 'Unknown Interrupt Vector',0 56 | 57 | str_console_prompt: 58 | defb 'TeensyZ80>',0 59 | 60 | ; interrupt vector table 61 | .ORG 0100h 62 | int_vector_table: 63 | dw ihdlr_unknown 64 | dw ihdlr_second_timer 65 | dw ihdlr_unknown 66 | dw ihdlr_unknown 67 | dw ihdlr_unknown 68 | dw ihdlr_unknown 69 | dw ihdlr_unknown 70 | dw ihdlr_unknown 71 | dw ihdlr_unknown 72 | dw ihdlr_unknown 73 | dw ihdlr_unknown 74 | dw ihdlr_unknown 75 | dw ihdlr_unknown 76 | dw ihdlr_unknown 77 | dw ihdlr_unknown 78 | dw ihdlr_unknown 79 | dw ihdlr_unknown 80 | dw ihdlr_unknown 81 | dw ihdlr_unknown 82 | dw ihdlr_unknown 83 | dw ihdlr_unknown 84 | dw ihdlr_unknown 85 | dw ihdlr_unknown 86 | dw ihdlr_unknown 87 | dw ihdlr_unknown 88 | dw ihdlr_unknown 89 | dw ihdlr_unknown 90 | dw ihdlr_unknown 91 | dw ihdlr_unknown 92 | dw ihdlr_unknown 93 | dw ihdlr_unknown 94 | dw ihdlr_unknown 95 | dw ihdlr_unknown 96 | dw ihdlr_unknown 97 | dw ihdlr_unknown 98 | dw ihdlr_unknown 99 | dw ihdlr_unknown 100 | dw ihdlr_unknown 101 | dw ihdlr_unknown 102 | dw ihdlr_unknown 103 | dw ihdlr_unknown 104 | dw ihdlr_unknown 105 | dw ihdlr_unknown 106 | dw ihdlr_unknown 107 | dw ihdlr_unknown 108 | dw ihdlr_unknown 109 | dw ihdlr_unknown 110 | dw ihdlr_unknown 111 | dw ihdlr_unknown 112 | dw ihdlr_unknown 113 | dw ihdlr_unknown 114 | dw ihdlr_unknown 115 | dw ihdlr_unknown 116 | dw ihdlr_unknown 117 | dw ihdlr_unknown 118 | dw ihdlr_unknown 119 | dw ihdlr_unknown 120 | dw ihdlr_unknown 121 | dw ihdlr_unknown 122 | dw ihdlr_unknown 123 | dw ihdlr_unknown 124 | dw ihdlr_unknown 125 | dw ihdlr_unknown 126 | dw ihdlr_unknown 127 | dw ihdlr_unknown 128 | dw ihdlr_unknown 129 | dw ihdlr_unknown 130 | dw ihdlr_unknown 131 | dw ihdlr_unknown 132 | dw ihdlr_unknown 133 | dw ihdlr_unknown 134 | dw ihdlr_unknown 135 | dw ihdlr_unknown 136 | dw ihdlr_unknown 137 | dw ihdlr_unknown 138 | dw ihdlr_unknown 139 | dw ihdlr_unknown 140 | dw ihdlr_unknown 141 | dw ihdlr_unknown 142 | dw ihdlr_unknown 143 | dw ihdlr_unknown 144 | dw ihdlr_unknown 145 | dw ihdlr_unknown 146 | dw ihdlr_unknown 147 | dw ihdlr_unknown 148 | dw ihdlr_unknown 149 | dw ihdlr_unknown 150 | dw ihdlr_unknown 151 | dw ihdlr_unknown 152 | dw ihdlr_unknown 153 | dw ihdlr_unknown 154 | dw ihdlr_unknown 155 | dw ihdlr_unknown 156 | dw ihdlr_unknown 157 | dw ihdlr_unknown 158 | dw ihdlr_unknown 159 | dw ihdlr_unknown 160 | dw ihdlr_unknown 161 | dw ihdlr_unknown 162 | dw ihdlr_unknown 163 | dw ihdlr_unknown 164 | dw ihdlr_unknown 165 | dw ihdlr_unknown 166 | dw ihdlr_unknown 167 | dw ihdlr_unknown 168 | dw ihdlr_unknown 169 | dw ihdlr_unknown 170 | dw ihdlr_unknown 171 | dw ihdlr_unknown 172 | dw ihdlr_unknown 173 | dw ihdlr_unknown 174 | dw ihdlr_unknown 175 | dw ihdlr_unknown 176 | dw ihdlr_unknown 177 | dw ihdlr_unknown 178 | dw ihdlr_unknown 179 | dw ihdlr_unknown 180 | dw ihdlr_unknown 181 | dw ihdlr_unknown 182 | dw ihdlr_unknown 183 | dw ihdlr_unknown 184 | dw ihdlr_unknown 185 | dw ihdlr_unknown 186 | dw ihdlr_unknown 187 | dw ihdlr_unknown 188 | dw ihdlr_unknown 189 | dw ihdlr_unknown 190 | dw ihdlr_unknown 191 | dw ihdlr_unknown 192 | dw ihdlr_unknown 193 | end -------------------------------------------------------------------------------- /z80/test_programs_asm/ls.z: -------------------------------------------------------------------------------- 1 | ; 2 | ; TeensyZ80 list directory program 3 | 4 | PORT_VRAM_BUFFER_LOC equ 0 5 | PORT_VRAM_DRAW equ 8 6 | 7 | PORT_FILESYS_READ_WRITE equ 10 8 | PORT_FILESYS_OPEN_CLOSE equ 11 9 | PORT_FILESYS_NEXT equ 12 10 | 11 | FILESYS_RW_EXEC equ 13 12 | FILESYS_RW_SETCMDMEMPTR equ 2 13 | FILESYS_OPEN_OPENFILE equ 5 14 | FILESYS_OPEN_SETMEMPTR equ 6 15 | FILESYS_NEXT_GETNEXT equ 9 16 | FILESYS_NEXT_SETMEMPTR equ 10 17 | FILESYS_CLOSE_FILE equ 12 18 | 19 | OPEN_READ equ 0 20 | OPEN_WRITE equ 1 21 | OPEN_WRITE_CREATE equ 2 22 | OPEN_APPEND equ 3 23 | OPEN_RDWR equ 4 24 | 25 | 26 | COLOUR_BLACK equ 00000h 27 | COLOUR_BLUE equ 0001Fh 28 | COLOUR_RED equ 0F800h 29 | COLOUR_GREEN equ 007E0h 30 | COLOUR_CYAN equ 007FFh 31 | COLOUR_MAGENTA equ 0F81Fh 32 | COLOUR_YELLOW equ 0FFE0h 33 | COLOUR_WHITE equ 0FFFFh 34 | 35 | VRAM_HIGH_BEGIN equ 04h ; vram at address 0x0400 36 | 37 | ; 38 | ; openfile expects 39 | ; 40 | ; openfile_cmd { 41 | ; 0: uint8_t error; // writes 42 | ; 1: uint32_t size; // writes 43 | ; 5: uint8_t type; // writes 44 | ; 6: uint8_t flags; // reads 45 | ; 7: char name[13]; // reads, null-terminated 46 | ; } 47 | ; 48 | ; getnext writes 49 | ; 50 | ; getnext_output { 51 | ; 0: uint8_t error; 52 | ; 1: uint32_t filesize; 53 | ; 5: uint8_t flags; 54 | ; 6: char name[13]; //null-terminated 55 | ; } 56 | ; 57 | ; read/write reads 58 | ; 59 | ; #define CMD_READ 0 60 | ; #define CMD_WRITE 1 61 | ; struct { 62 | ; 0: uint8_t error_code; // writes 63 | ; 1: uint8_t op_type; // CMD_READ or CMD_WRITE 64 | ; 2: uint16_t file_offset; //ignored if OPEN_APPEND 65 | ; 4: uint16_t block_size; 66 | ; 6: uint16_t mem_buffer_ptr; 67 | ; } 68 | ; 69 | 70 | .org 01000h 71 | start: 72 | ; open the root dir as a file 73 | ld a, FILESYS_OPEN_SETMEMPTR 74 | out (PORT_FILESYS_OPEN_CLOSE), a 75 | ld de, filesys_root_dir_open 76 | ld a, e 77 | out (PORT_FILESYS_OPEN_CLOSE), a 78 | ld a, d 79 | out (PORT_FILESYS_OPEN_CLOSE), a 80 | ld a, FILESYS_OPEN_OPENFILE 81 | out (PORT_FILESYS_OPEN_CLOSE), a 82 | ld a, (de) ; load the error byte 83 | or a 84 | jr z, L01 ; if successful jump over the fail 85 | Lfile_fail: 86 | add a, 30h ; get ascii 0-9 87 | out ($03), a 88 | call file_error_report 89 | L01: 90 | 91 | ld a, FILESYS_NEXT_SETMEMPTR 92 | out (PORT_FILESYS_NEXT), a 93 | ld de, scratch_mem 94 | ld a, e 95 | out (PORT_FILESYS_NEXT), a 96 | ld a, d 97 | out (PORT_FILESYS_NEXT), a 98 | ld hl, scratch_mem 99 | ld de, scratch_mem + 6 100 | getnextfile: 101 | ld a, FILESYS_NEXT_GETNEXT 102 | out (PORT_FILESYS_NEXT), a 103 | ld a, (hl) 104 | or a 105 | jr nz, nomorefiles 106 | ld a, 4 107 | out ($05), a ; tab in 108 | call print_string ; prints string at bc 109 | call newline 110 | jr getnextfile 111 | nomorefiles: 112 | ld a, FILESYS_CLOSE_FILE 113 | out (PORT_FILESYS_OPEN_CLOSE), a 114 | call newline 115 | ld a, 0 116 | out ($05), a ; tab out 117 | 118 | ld de, aaron_lol 119 | 120 | call print_string 121 | ret 122 | 123 | 124 | print_string: 125 | push af 126 | push de 127 | print_string_loop: 128 | ld a, (de) 129 | or a 130 | jr z, print_string_end 131 | out ($03), a 132 | inc de 133 | jr print_string_loop 134 | print_string_end: 135 | pop de 136 | pop af 137 | ret 138 | 139 | newline: 140 | push af 141 | in a, ($04) 142 | inc a 143 | out ($04), a 144 | ld a, 0 145 | out ($05), a 146 | pop af 147 | ret 148 | 149 | file_error_report: 150 | call newline 151 | ld de, str_error_file 152 | call print_string 153 | call fatal_error_halt 154 | ret 155 | 156 | fatal_error_halt: 157 | call newline 158 | ld bc, COLOUR_RED 159 | call setcolour 160 | ld de, str_halt 161 | call print_string 162 | fatal_error_halt_1: 163 | halt 164 | jr fatal_error_halt_1 165 | 166 | setcolour: ;16-bit colour in bc 167 | push af 168 | ld a, b 169 | out ($06), a 170 | ld a, c 171 | out ($06), a 172 | pop af 173 | ret 174 | 175 | str_console_prompt: 176 | defb 'TeensyZ80> ',0 177 | 178 | file_desc: 179 | defb 'SD:/',0 180 | 181 | readme_desc: 182 | defb 'contents of README.TXT:',0 183 | 184 | str_write_file: 185 | defb 'Writing to TEST.TXT...',0 186 | 187 | str_write_file_OK: 188 | defb 'OK',0 189 | 190 | str_error_file: 191 | defb 'Filesystem error!',0 192 | 193 | str_halt: 194 | defb 'Fatal Error. ',0 195 | 196 | filesys_root_dir_open: 197 | defb 0ffh,0,0,0,0,0,OPEN_READ,'/',0,0,0 ; error byte (init to error), open type byte, filename 8.3, null 198 | 199 | filesys_readme_open_read: 200 | defb 0ffh,0,0,0,0,0,OPEN_READ,'README.TXT',0,0,0 201 | 202 | filesys_test_open_write: 203 | defb 0ffh,0,0,0,0,0,OPEN_WRITE_CREATE,'TEST.TXT',0,0,0,0,0,0 204 | 205 | filesys_speccy_open_read: 206 | defb 0ffh,0,0,0,0,0,OPEN_READ,'SPECCY.565',0,0,0 207 | 208 | filesys_read_request: 209 | ; error, type, offsetlo,offsethi,sizelo,sizehi 210 | defb 0ffh,0,0,0,0,0 211 | defw scratch_mem 212 | 213 | filesys_write_request: 214 | ; error, type, offsetlo,offsethi,sizelo,sizehi 215 | defb 0ffh,1,0,0,8,0 216 | defw test_string 217 | 218 | filesys_speccy_read_req: 219 | ; error, type, offsetlo,offsethi,sizelo,sizehi 220 | defb 0ffh,0,0,0,0,0 221 | defb 0, VRAM_HIGH_BEGIN 222 | 223 | test_string: 224 | defb '0123456',0 225 | 226 | aaron_lol: 227 | defb 'Hay Aaron! lel',0 228 | 229 | scratch_mem: 230 | 231 | end -------------------------------------------------------------------------------- /z80/z80os.z: -------------------------------------------------------------------------------- 1 | ; Simple Z80 bootloader/OS for Z80Teensy project 2 | 3 | SERIAL_CMD_SET_INTVECTOR equ 0F1h 4 | SERIAL_CMD_SET_RATE equ 0F2h 5 | SERIAL_CMD_INIT equ 0FAh 6 | 7 | INTVECTOR_SERIAL_DEVICE equ 2 8 | 9 | 10 | PORT_RAM_BANK_SET equ 200 11 | 12 | PORT_VRAM_BUFFER_LOC equ 0 13 | PORT_VRAM_DRAW equ 8 14 | 15 | PORT_MEM_SIZE equ 100 16 | 17 | PORT_DISP_CLEAR equ 20 18 | 19 | PORT_FILESYS_READ_WRITE equ 10 20 | PORT_FILESYS_OPEN_CLOSE equ 11 21 | PORT_FILESYS_NEXT equ 12 22 | 23 | FILESYS_RW_EXEC equ 13 24 | FILESYS_RW_SETCMDMEMPTR equ 2 25 | FILESYS_OPEN_OPENFILE equ 5 26 | FILESYS_OPEN_SETMEMPTR equ 6 27 | FILESYS_NEXT_GETNEXT equ 9 28 | FILESYS_NEXT_SETMEMPTR equ 10 29 | FILESYS_CLOSE_FILE equ 12 30 | 31 | OPEN_READ equ 0 32 | OPEN_WRITE equ 1 33 | OPEN_WRITE_CREATE equ 2 34 | OPEN_APPEND equ 3 35 | OPEN_RDWR equ 4 36 | 37 | COLOUR_BLACK equ 00000h 38 | COLOUR_BLUE equ 0001Fh 39 | COLOUR_RED equ 0F800h 40 | COLOUR_GREEN equ 007E0h 41 | COLOUR_CYAN equ 007FFh 42 | COLOUR_MAGENTA equ 0F81Fh 43 | COLOUR_YELLOW equ 0FFE0h 44 | COLOUR_WHITE equ 0FFFFh 45 | 46 | 47 | PROG_MEM_START equ 01000h 48 | 49 | .org 0000h 50 | start: 51 | di 52 | ld sp, 3fffh 53 | ld a, 0Bh 54 | ld I, a 55 | 56 | ld de, str_boot_msg 57 | call print_string 58 | call newline 59 | 60 | ld de, str_console_setup 61 | call print_string 62 | ld a, 36 63 | out ($05), a 64 | ld b, 0E0h 65 | ld c, 07h 66 | call setcolour 67 | ld de, str_ok_boot 68 | call print_string 69 | call newline 70 | 71 | ld b, 0FFh 72 | ld c, 0FFh 73 | call setcolour 74 | 75 | out ($00), a ;set the high byte to the console for the display printer 76 | 77 | 78 | ld de, str_configure_serial 79 | call print_string 80 | ld a, 36 81 | out ($05), a 82 | 83 | ; 84 | ; Set up and initialize the serial device 85 | ; 86 | ;ld a, SERIAL_CMD_SET_INTVECTOR 87 | ;out ($01), a ; put the serial device in SET_INTVECTOR mode 88 | ;ld a, INTVECTOR_SERIAL_DEVICE 89 | ;out ($01), a ;set the serial in interrupt vector 90 | 91 | 92 | ld a, SERIAL_CMD_SET_RATE 93 | out ($01), a ; set the serial rate (9600) 94 | ld a, 80h 95 | out ($01), a 96 | ld a, 25h 97 | out ($01), a 98 | 99 | 100 | ld b, 0E0h 101 | ld c, 07h 102 | call setcolour 103 | ld de, str_ok_boot 104 | call print_string 105 | call newline 106 | 107 | 108 | ld b, 0FFh 109 | ld c, 0FFh 110 | call setcolour 111 | ld de, str_connect_serial_wait 112 | call print_string 113 | ld a, 36 114 | out ($05), a 115 | 116 | ld a, SERIAL_CMD_INIT 117 | out ($01), a ; init the serial device 118 | ld a, 2Bh 119 | out ($02), a ; print + to serial 120 | 121 | 122 | ld b, 0E0h 123 | ld c, 07h 124 | call setcolour 125 | ld de, str_ok_boot 126 | call print_string 127 | call newline 128 | 129 | 130 | ld b, 0FFh 131 | ld c, 0FFh 132 | call setcolour 133 | 134 | 135 | ld de, str_connect_serial_ok 136 | call print_string 137 | call newline 138 | 139 | 140 | open_volume_root_dir: 141 | ld a, FILESYS_OPEN_SETMEMPTR 142 | out (PORT_FILESYS_OPEN_CLOSE), a 143 | ld de, filesys_root_dir_open 144 | ld a, e 145 | out (PORT_FILESYS_OPEN_CLOSE), a 146 | ld a, d 147 | out (PORT_FILESYS_OPEN_CLOSE), a 148 | ld a, FILESYS_OPEN_OPENFILE 149 | out (PORT_FILESYS_OPEN_CLOSE), a 150 | ld a, (de) ; load the error byte 151 | or a 152 | jp nz, Lfile_fail ; if non-zero jump to fail 153 | 154 | 155 | ld a, FILESYS_CLOSE_FILE 156 | out (PORT_FILESYS_OPEN_CLOSE), a 157 | 158 | 159 | call newline 160 | 161 | im 2 162 | ei 163 | ld de, str_console_banner_1 164 | call print_string 165 | call newline 166 | ld de, str_console_banner_2 167 | call print_string 168 | 169 | call newline 170 | prompt_begin: 171 | call console_clearbuffer 172 | call newline 173 | ld de, str_console_prompt 174 | call print_string 175 | 176 | echo_serial: 177 | call getchar 178 | cp 13 ;carriage return? 179 | jr z, parse_command 180 | call console_addchar 181 | call putchar 182 | jr echo_serial 183 | 184 | parse_command: 185 | ; for now, shove the 12 chars into the open request. 186 | ; de = src ptr 187 | ; hl = dst ptr 188 | ; bc = size 189 | ld de, console_line_buffer 190 | ld hl, filesys_open_read_name 191 | ld bc, 12 192 | call memcpy 193 | 194 | call newline 195 | open_file: 196 | ld a, FILESYS_OPEN_SETMEMPTR 197 | out (PORT_FILESYS_OPEN_CLOSE), a 198 | ld de, filesys_open_read 199 | ld a, e 200 | out (PORT_FILESYS_OPEN_CLOSE), a 201 | ld a, d 202 | out (PORT_FILESYS_OPEN_CLOSE), a 203 | ld a, FILESYS_OPEN_OPENFILE 204 | out (PORT_FILESYS_OPEN_CLOSE), a 205 | ld a, (de) ; load the error byte 206 | or a 207 | jr nz, Lfile_fail_cmd ; if non-zero jump to fail above 208 | 209 | 210 | ld de, filesys_open_read + 1 211 | ld hl, filesys_read_request + 4 212 | ld a, (de) 213 | ld (hl), a 214 | inc de 215 | inc hl 216 | ld a, (de) 217 | ld (hl), a 218 | 219 | 220 | read_file: 221 | ld a, FILESYS_RW_SETCMDMEMPTR 222 | out (PORT_FILESYS_READ_WRITE), a 223 | ld de, filesys_read_request 224 | ld a, e 225 | out (PORT_FILESYS_READ_WRITE), a 226 | ld a, d 227 | out (PORT_FILESYS_READ_WRITE), a 228 | ld a, FILESYS_RW_EXEC 229 | out (PORT_FILESYS_READ_WRITE), a 230 | ld a, (de) ; load the error byte 231 | or a 232 | jr nz, Lfile_fail ; if non-zero jump to fail above 233 | 234 | ld a, FILESYS_CLOSE_FILE 235 | out (PORT_FILESYS_OPEN_CLOSE), a 236 | 237 | call PROG_MEM_START 238 | 239 | ;ld a, 0 240 | ;out (PORT_DISP_CLEAR), a 241 | jr prompt_begin 242 | 243 | infloop: ; halt (wait for interrupts) 244 | halt 245 | jr infloop 246 | 247 | Lfile_fail: ; error code (0-9) in a 248 | call file_error_report 249 | jr prompt_begin 250 | 251 | Lfile_fail_cmd: ; error code (0-9) in a 252 | push de 253 | ld b, 000h 254 | ld c, 0F8h 255 | call setcolour 256 | ld de, str_error_code 257 | call print_string 258 | add a, 30h ; get ascii 0-9 259 | out ($03), a ;code 260 | ld de, str_error_opening 261 | call print_string 262 | ld de, console_line_buffer 263 | call print_string 264 | ld b, 0FFh 265 | ld c, 0FFh 266 | call setcolour 267 | pop de 268 | jp prompt_begin 269 | 270 | file_error_report: 271 | ld de, str_error_file 272 | call print_string 273 | ;;call fatal_error_halt 274 | ret 275 | 276 | fatal_error_halt: 277 | call newline 278 | ld bc, COLOUR_RED 279 | call setcolour 280 | ld de, str_halt 281 | call print_string 282 | fatal_error_halt_1: 283 | halt 284 | jr fatal_error_halt_1 285 | 286 | strcpy: 287 | push af 288 | strcpy_loop: 289 | ld a, (de) 290 | ld (hl), a 291 | inc hl 292 | inc de 293 | or a 294 | jr nz,strcpy_loop 295 | pop af 296 | ret 297 | 298 | ; de = src ptr 299 | ; hl = dst ptr 300 | ; bc = size 301 | memcpy: 302 | push af 303 | push de 304 | push hl 305 | push bc 306 | memcpy_loop: 307 | ld a, b 308 | or c 309 | jr z, memcpy_end 310 | dec bc 311 | ld a, (de) 312 | ld (hl), a 313 | inc hl 314 | inc de 315 | jr memcpy_loop 316 | memcpy_end: 317 | pop bc 318 | pop hl 319 | pop de 320 | pop af 321 | ret 322 | 323 | ; d = src byte 324 | ; hl = dst ptr 325 | ; bc = size 326 | memset: 327 | push af 328 | push de 329 | push hl 330 | push bc 331 | memset_loop: 332 | ld a, b 333 | or c 334 | jr z, memset_end 335 | dec bc 336 | ld a, d 337 | ld (hl), a 338 | inc hl 339 | jr memset_loop 340 | memset_end: 341 | pop bc 342 | pop hl 343 | pop de 344 | pop af 345 | ret 346 | 347 | print_string: 348 | push af 349 | print_string_loop: 350 | ld a, (de) 351 | or a 352 | jr z, print_string_end 353 | out ($03), a 354 | inc de 355 | jr print_string_loop 356 | print_string_end: 357 | pop af 358 | ret 359 | 360 | 361 | ihdlr_unknown: 362 | di 363 | push de 364 | ld de, str_unknownint 365 | call print_string 366 | pop de 367 | ei 368 | reti 369 | 370 | 371 | ihdlr_ignore: 372 | di 373 | ei 374 | reti 375 | 376 | ihdlr_serial_in: 377 | di 378 | push af 379 | push bc 380 | ;push de 381 | ; read from serial status port 382 | in a, ($01) 383 | or a 384 | jr z, skip_serial_in 385 | ld b, a 386 | ;ld de, cbuffer 387 | print_serial_char: 388 | ; read char from serial data port 389 | in a, ($02) 390 | ; echo it to console 391 | out ($03), a 392 | ;ld (de), a 393 | ;inc de 394 | djnz print_serial_char 395 | skip_serial_in: 396 | ;pop de 397 | pop bc 398 | pop af 399 | ei 400 | reti 401 | 402 | ihdlr_second_timer: 403 | di 404 | push af 405 | ld a, 02eh ;print period to console 406 | out ($03), a 407 | pop af 408 | ei 409 | reti 410 | 411 | getchar: ; returns char in a register 412 | in a, ($01) ; read from serial status port 413 | or a 414 | jr z, getchar ; while no data is available, wait 415 | in a, ($02) ; read char from serial data port 416 | ret 417 | 418 | putchar: ; char passed in a register 419 | out ($03), a ; simply write the char to output 420 | ret 421 | 422 | newline: 423 | in a, ($04) 424 | inc a 425 | out ($04), a 426 | ld a, 0 427 | out ($05), a 428 | ret 429 | 430 | setcolour: ;16-bit colour in bc 431 | push af 432 | ld a, b 433 | out ($06), a 434 | ld a, c 435 | out ($06), a 436 | pop af 437 | ret 438 | 439 | str_unknownint: 440 | defb 'Unknown Interrupt Vector',0 441 | 442 | str_ok_boot: 443 | defb '[OK]',0 444 | 445 | str_done_boot: 446 | defb '[DONE]',0 447 | 448 | str_error_boot: 449 | defb '[ERROR]',0 450 | 451 | str_boot_msg: 452 | defb 'TeensyZ80 booting...',0 453 | 454 | str_console_setup: 455 | defb 'Console initializing...',0 456 | 457 | str_configure_serial: 458 | defb 'Configuring serial connection...',0 459 | 460 | str_connect_serial_wait: 461 | defb 'Waiting for serial connection...',0 462 | 463 | str_connect_serial_ok: 464 | defb 'Serial connection established.',0 465 | 466 | str_console_banner_1: 467 | defb 'Copyright(C) Domipheus Labs',0 468 | 469 | str_console_banner_2: 470 | defb 'Welcome to TeensyZ80!',0 471 | 472 | str_console_prompt: 473 | defb 'TeensyZ80>',0 474 | 475 | str_error_code: 476 | defb 'Error code: ',0 477 | 478 | str_error_opening: 479 | defb ' whilst opening: ',0 480 | 481 | str_error_file: 482 | defb 'Filesystem error!',0 483 | 484 | str_halt: 485 | defb 'Fatal Error. ',0 486 | 487 | ; interrupt vector table 488 | .ORG 0B00h 489 | int_vector_table: 490 | dw ihdlr_ignore 491 | dw ihdlr_ignore 492 | dw ihdlr_unknown 493 | dw ihdlr_unknown 494 | dw ihdlr_unknown 495 | dw ihdlr_unknown 496 | dw ihdlr_unknown 497 | dw ihdlr_unknown 498 | dw ihdlr_unknown 499 | dw ihdlr_unknown 500 | dw ihdlr_unknown 501 | dw ihdlr_unknown 502 | dw ihdlr_unknown 503 | dw ihdlr_unknown 504 | 505 | 506 | ; console line 507 | 508 | 509 | console_line_current_row: 510 | defb 0 511 | console_line_buffer_pos: 512 | defb 0 513 | 514 | .ORG 0C00h 515 | console_line_buffer: 516 | dc 256, 0 517 | 518 | console_addchar: ;char in a 519 | push hl 520 | push bc 521 | ld bc, console_line_buffer 522 | ld hl, console_line_buffer_pos 523 | ld c, (hl) 524 | ld (bc), a 525 | inc c 526 | ld (hl), c 527 | pop bc 528 | pop hl 529 | ret 530 | 531 | console_clearbuffer: 532 | ; d = src byte 533 | ; hl = dst ptr 534 | ; bc = size 535 | push de 536 | push hl 537 | push bc 538 | ld d, 0 539 | ld hl, console_line_buffer 540 | ld bc, 256 541 | call memset 542 | ld hl, console_line_buffer_pos 543 | ld (hl), 0 544 | pop bc 545 | pop hl 546 | pop de 547 | ret 548 | 549 | .org 0d00h 550 | SysFuncTable: 551 | dw 1 552 | dw getchar 553 | dw putchar 554 | 555 | filesys_root_dir_open: 556 | defb 0ffh,0,0,0,0,0,OPEN_READ,'/',0,0,0 ; error byte (init to error), open type byte, filename 8.3, null 557 | 558 | 559 | filesys_open_read: 560 | defb 0ffh,0,0,0,0,0,OPEN_READ,'abcdef.BIN',0,0,0 561 | filesys_open_read_name equ (filesys_open_read+7) 562 | 563 | filesys_read_request: 564 | ; error, type, offsetlo,offsethi,sizelo,sizehi 565 | defb 0ffh,0,0,0,0,0 566 | defw PROG_MEM_START 567 | 568 | end -------------------------------------------------------------------------------- /z80/z80listfiles.z: -------------------------------------------------------------------------------- 1 | ; 2 | ; TeensyZ80 SD files test 3 | ; prints directory listing of / to console 4 | ; print contents of /README.TXT 5 | ; display SPECCY.565 to a fixed test vram 6 | ; write "0123456\0" to /TEST.TXT 7 | 8 | PORT_VRAM_BUFFER_LOC equ 0 9 | PORT_VRAM_DRAW equ 8 10 | 11 | PORT_FILESYS_READ_WRITE equ 10 12 | PORT_FILESYS_OPEN_CLOSE equ 11 13 | PORT_FILESYS_NEXT equ 12 14 | 15 | FILESYS_RW_EXEC equ 13 16 | FILESYS_RW_SETCMDMEMPTR equ 2 17 | FILESYS_OPEN_OPENFILE equ 5 18 | FILESYS_OPEN_SETMEMPTR equ 6 19 | FILESYS_NEXT_GETNEXT equ 9 20 | FILESYS_NEXT_SETMEMPTR equ 10 21 | FILESYS_CLOSE_FILE equ 12 22 | 23 | OPEN_READ equ 0 24 | OPEN_WRITE equ 1 25 | OPEN_WRITE_CREATE equ 2 26 | OPEN_APPEND equ 3 27 | OPEN_RDWR equ 4 28 | 29 | 30 | COLOUR_BLACK equ 00000h 31 | COLOUR_BLUE equ 0001Fh 32 | COLOUR_RED equ 0F800h 33 | COLOUR_GREEN equ 007E0h 34 | COLOUR_CYAN equ 007FFh 35 | COLOUR_MAGENTA equ 0F81Fh 36 | COLOUR_YELLOW equ 0FFE0h 37 | COLOUR_WHITE equ 0FFFFh 38 | 39 | VRAM_HIGH_BEGIN equ 04h ; vram at address 0x0400 40 | 41 | ; 42 | ; openfile expects 43 | ; 44 | ; openfile_cmd { 45 | ; 0: uint8_t error; // writes 46 | ; 1: uint32_t size; // writes 47 | ; 5: uint8_t type; // writes 48 | ; 6: uint8_t flags; // reads 49 | ; 7: char name[13]; // reads, null-terminated 50 | ; } 51 | ; 52 | ; getnext writes 53 | ; 54 | ; getnext_output { 55 | ; 0: uint8_t error; 56 | ; 1: uint32_t filesize; 57 | ; 5: uint8_t flags; 58 | ; 6: char name[13]; //null-terminated 59 | ; } 60 | ; 61 | ; read/write reads 62 | ; 63 | ; #define CMD_READ 0 64 | ; #define CMD_WRITE 1 65 | ; struct { 66 | ; 0: uint8_t error_code; // writes 67 | ; 1: uint8_t op_type; // CMD_READ or CMD_WRITE 68 | ; 2: uint16_t file_offset; //ignored if OPEN_APPEND 69 | ; 4: uint16_t block_size; 70 | ; 6: uint16_t mem_buffer_ptr; 71 | ; } 72 | ; 73 | 74 | .org 0000h 75 | start: 76 | di 77 | ld sp, 3fffh 78 | im 2 79 | ld a, 02h 80 | ld I, a 81 | ld de, str_console_prompt 82 | call print_string 83 | call newline 84 | ld de, file_desc 85 | call print_string 86 | 87 | ld a, VRAM_HIGH_BEGIN 88 | out (PORT_VRAM_BUFFER_LOC), a ; 'vram' starts here 89 | 90 | ; open the root dir as a file 91 | ld a, FILESYS_OPEN_SETMEMPTR 92 | out (PORT_FILESYS_OPEN_CLOSE), a 93 | ld de, filesys_root_dir_open 94 | ld a, e 95 | out (PORT_FILESYS_OPEN_CLOSE), a 96 | ld a, d 97 | out (PORT_FILESYS_OPEN_CLOSE), a 98 | ld a, FILESYS_OPEN_OPENFILE 99 | out (PORT_FILESYS_OPEN_CLOSE), a 100 | ld a, (de) ; load the error byte 101 | or a 102 | jr z, L01 ; if successful jump over the fail 103 | Lfile_fail: 104 | add a, 30h ; get ascii 0-9 105 | out ($03), a 106 | call file_error_report 107 | L01: 108 | 109 | ld a, FILESYS_NEXT_SETMEMPTR 110 | out (PORT_FILESYS_NEXT), a 111 | ld de, scratch_mem 112 | ld a, e 113 | out (PORT_FILESYS_NEXT), a 114 | ld a, d 115 | out (PORT_FILESYS_NEXT), a 116 | ld hl, scratch_mem 117 | ld de, scratch_mem + 6 118 | getnextfile: 119 | call newline 120 | ld a, FILESYS_NEXT_GETNEXT 121 | out (PORT_FILESYS_NEXT), a 122 | ld a, (hl) 123 | or a 124 | jr nz, nomorefiles 125 | call print_string ; prints string at bc 126 | jr getnextfile 127 | nomorefiles: 128 | ld a, FILESYS_CLOSE_FILE 129 | out (PORT_FILESYS_OPEN_CLOSE), a 130 | call newline 131 | call newline 132 | 133 | ld de, str_console_prompt 134 | call print_string 135 | 136 | 137 | call newline 138 | ld de, readme_desc 139 | call print_string 140 | 141 | loadreadme: 142 | ld a, FILESYS_OPEN_SETMEMPTR 143 | out (PORT_FILESYS_OPEN_CLOSE), a 144 | ld de, filesys_readme_open_read 145 | ld a, e 146 | out (PORT_FILESYS_OPEN_CLOSE), a 147 | ld a, d 148 | out (PORT_FILESYS_OPEN_CLOSE), a 149 | ld a, FILESYS_OPEN_OPENFILE 150 | out (PORT_FILESYS_OPEN_CLOSE), a 151 | ld a, (de) ; load the error byte 152 | or a 153 | jr nz, Lfile_fail ; if non-zero jump to fail above 154 | 155 | call newline 156 | 157 | ; assume < 256b file for now 158 | ld de, filesys_readme_open_read + 1 159 | ld a, (de) 160 | 161 | ld hl, filesys_read_request+4 162 | ld (hl), a 163 | 164 | ld a, FILESYS_RW_SETCMDMEMPTR 165 | out (PORT_FILESYS_READ_WRITE), a 166 | ld de, filesys_read_request 167 | ld a, e 168 | out (PORT_FILESYS_READ_WRITE), a 169 | ld a, d 170 | out (PORT_FILESYS_READ_WRITE), a 171 | ld a, FILESYS_RW_EXEC 172 | out (PORT_FILESYS_READ_WRITE), a 173 | ld a, (de) ; load the error byte 174 | or a 175 | jr nz, Lfile_fail ; if non-zero jump to fail above 176 | 177 | ld de, scratch_mem ; the cmd instructed to read into scratch 178 | call print_string 179 | call newline 180 | 181 | ld a, FILESYS_CLOSE_FILE 182 | out (PORT_FILESYS_OPEN_CLOSE), a ; close README.txt 183 | 184 | 185 | ; load an image called 'speccy.565' 186 | 187 | ld a, FILESYS_OPEN_SETMEMPTR 188 | out (PORT_FILESYS_OPEN_CLOSE), a 189 | ld de, filesys_speccy_open_read 190 | ld a, e 191 | out (PORT_FILESYS_OPEN_CLOSE), a 192 | ld a, d 193 | out (PORT_FILESYS_OPEN_CLOSE), a 194 | ld a, FILESYS_OPEN_OPENFILE 195 | out (PORT_FILESYS_OPEN_CLOSE), a 196 | ld a, (de) ; load the error byte 197 | or a 198 | jp nz, Lfile_fail ; if non-zero jump to fail above 199 | 200 | call newline 201 | 202 | ld de, filesys_speccy_open_read + 1 203 | ld hl, filesys_speccy_read_req + 4 204 | ld a, (de) 205 | ld (hl), a 206 | inc de 207 | inc hl 208 | ld a, (de) 209 | ld (hl), a 210 | 211 | 212 | ld a, FILESYS_RW_SETCMDMEMPTR 213 | out (PORT_FILESYS_READ_WRITE), a 214 | ld de, filesys_speccy_read_req 215 | ld a, e 216 | out (PORT_FILESYS_READ_WRITE), a 217 | ld a, d 218 | out (PORT_FILESYS_READ_WRITE), a 219 | ld a, FILESYS_RW_EXEC 220 | out (PORT_FILESYS_READ_WRITE), a 221 | ld a, (de) ; load the error byte 222 | or a 223 | jp nz, Lfile_fail ; if non-zero jump to fail above 224 | 225 | ld a, FILESYS_CLOSE_FILE 226 | out (PORT_FILESYS_OPEN_CLOSE), a 227 | 228 | writefile: 229 | ld a, FILESYS_OPEN_SETMEMPTR 230 | out (PORT_FILESYS_OPEN_CLOSE), a 231 | ld de, filesys_test_open_write 232 | ld a, e 233 | out (PORT_FILESYS_OPEN_CLOSE), a 234 | ld a, d 235 | out (PORT_FILESYS_OPEN_CLOSE), a 236 | ld a, FILESYS_OPEN_OPENFILE 237 | out (PORT_FILESYS_OPEN_CLOSE), a 238 | ld a, (de) ; load the error byte 239 | or a 240 | jp nz, Lfile_fail ; if non-zero jump to fail above 241 | 242 | call newline 243 | 244 | ld de, str_write_file 245 | call print_string 246 | 247 | ld a, FILESYS_RW_SETCMDMEMPTR 248 | out (PORT_FILESYS_READ_WRITE), a 249 | ld de, filesys_write_request 250 | ld a, e 251 | out (PORT_FILESYS_READ_WRITE), a 252 | ld a, d 253 | out (PORT_FILESYS_READ_WRITE), a 254 | ld a, FILESYS_RW_EXEC 255 | out (PORT_FILESYS_READ_WRITE), a 256 | ld a, (de) ; load the error byte 257 | or a 258 | jp nz, Lfile_fail ; if non-zero jump to fail above 259 | 260 | ld a, FILESYS_CLOSE_FILE 261 | out (PORT_FILESYS_OPEN_CLOSE), a 262 | 263 | 264 | 265 | ld de, str_write_file_OK 266 | call print_string 267 | 268 | ld a, 0 269 | out (PORT_VRAM_DRAW), a ; draw vram 270 | 271 | 272 | ei 273 | iloop: 274 | halt 275 | jr iloop 276 | 277 | 278 | print_string: 279 | push af 280 | push de 281 | print_string_loop: 282 | ld a, (de) 283 | or a 284 | jr z, print_string_end 285 | out ($03), a 286 | inc de 287 | jr print_string_loop 288 | print_string_end: 289 | pop de 290 | pop af 291 | ret 292 | 293 | newline: 294 | push af 295 | in a, ($04) 296 | inc a 297 | out ($04), a 298 | ld a, 0 299 | out ($05), a 300 | pop af 301 | ret 302 | 303 | ihdlr_ignore: 304 | di 305 | ei 306 | reti 307 | 308 | ihdlr_unknown: 309 | di 310 | push de 311 | ld de, str_unknownint 312 | call print_string 313 | pop de 314 | ei 315 | reti 316 | 317 | str_unknownint: 318 | defb 'Unknown Interrupt Vector',0 319 | 320 | 321 | 322 | ; interrupt vector table 323 | .ORG 0200h 324 | int_vector_table: 325 | dw ihdlr_unknown 326 | dw ihdlr_ignore ;fired every second, ignore it 327 | dw ihdlr_unknown 328 | dw ihdlr_unknown 329 | dw ihdlr_unknown 330 | dw ihdlr_unknown 331 | dw ihdlr_unknown 332 | dw ihdlr_unknown 333 | dw ihdlr_unknown 334 | dw ihdlr_unknown 335 | dw ihdlr_unknown 336 | dw ihdlr_unknown 337 | dw ihdlr_unknown 338 | dw ihdlr_unknown 339 | dw ihdlr_unknown 340 | dw ihdlr_unknown 341 | dw ihdlr_unknown 342 | dw ihdlr_unknown 343 | dw ihdlr_unknown 344 | dw ihdlr_unknown 345 | dw ihdlr_unknown 346 | dw ihdlr_unknown 347 | dw ihdlr_unknown 348 | dw ihdlr_unknown 349 | dw ihdlr_unknown 350 | dw ihdlr_unknown 351 | dw ihdlr_unknown 352 | dw ihdlr_unknown 353 | dw ihdlr_unknown 354 | dw ihdlr_unknown 355 | dw ihdlr_unknown 356 | dw ihdlr_unknown 357 | dw ihdlr_unknown 358 | dw ihdlr_unknown 359 | dw ihdlr_unknown 360 | dw ihdlr_unknown 361 | dw ihdlr_unknown 362 | dw ihdlr_unknown 363 | dw ihdlr_unknown 364 | dw ihdlr_unknown 365 | dw ihdlr_unknown 366 | dw ihdlr_unknown 367 | dw ihdlr_unknown 368 | dw ihdlr_unknown 369 | dw ihdlr_unknown 370 | dw ihdlr_unknown 371 | dw ihdlr_unknown 372 | dw ihdlr_unknown 373 | dw ihdlr_unknown 374 | dw ihdlr_unknown 375 | dw ihdlr_unknown 376 | dw ihdlr_unknown 377 | dw ihdlr_unknown 378 | dw ihdlr_unknown 379 | dw ihdlr_unknown 380 | dw ihdlr_unknown 381 | dw ihdlr_unknown 382 | dw ihdlr_unknown 383 | dw ihdlr_unknown 384 | dw ihdlr_unknown 385 | dw ihdlr_unknown 386 | dw ihdlr_unknown 387 | dw ihdlr_unknown 388 | dw ihdlr_unknown 389 | dw ihdlr_unknown 390 | dw ihdlr_unknown 391 | dw ihdlr_unknown 392 | dw ihdlr_unknown 393 | dw ihdlr_unknown 394 | dw ihdlr_unknown 395 | dw ihdlr_unknown 396 | dw ihdlr_unknown 397 | dw ihdlr_unknown 398 | dw ihdlr_unknown 399 | dw ihdlr_unknown 400 | dw ihdlr_unknown 401 | dw ihdlr_unknown 402 | dw ihdlr_unknown 403 | dw ihdlr_unknown 404 | dw ihdlr_unknown 405 | dw ihdlr_unknown 406 | dw ihdlr_unknown 407 | dw ihdlr_unknown 408 | dw ihdlr_unknown 409 | dw ihdlr_unknown 410 | dw ihdlr_unknown 411 | dw ihdlr_unknown 412 | dw ihdlr_unknown 413 | dw ihdlr_unknown 414 | dw ihdlr_unknown 415 | dw ihdlr_unknown 416 | dw ihdlr_unknown 417 | dw ihdlr_unknown 418 | dw ihdlr_unknown 419 | dw ihdlr_unknown 420 | dw ihdlr_unknown 421 | dw ihdlr_unknown 422 | dw ihdlr_unknown 423 | dw ihdlr_unknown 424 | dw ihdlr_unknown 425 | dw ihdlr_unknown 426 | dw ihdlr_unknown 427 | dw ihdlr_unknown 428 | dw ihdlr_unknown 429 | dw ihdlr_unknown 430 | dw ihdlr_unknown 431 | dw ihdlr_unknown 432 | dw ihdlr_unknown 433 | dw ihdlr_unknown 434 | dw ihdlr_unknown 435 | dw ihdlr_unknown 436 | dw ihdlr_unknown 437 | dw ihdlr_unknown 438 | dw ihdlr_unknown 439 | dw ihdlr_unknown 440 | dw ihdlr_unknown 441 | dw ihdlr_unknown 442 | dw ihdlr_unknown 443 | dw ihdlr_unknown 444 | dw ihdlr_unknown 445 | dw ihdlr_unknown 446 | dw ihdlr_unknown 447 | dw ihdlr_unknown 448 | dw ihdlr_unknown 449 | dw ihdlr_unknown 450 | dw ihdlr_unknown 451 | dw ihdlr_unknown 452 | dw ihdlr_unknown 453 | dw ihdlr_unknown 454 | dw ihdlr_unknown 455 | 456 | 457 | file_error_report: 458 | call newline 459 | ld de, str_error_file 460 | call print_string 461 | call fatal_error_halt 462 | ret 463 | 464 | fatal_error_halt: 465 | call newline 466 | ld bc, COLOUR_RED 467 | call setcolour 468 | ld de, str_halt 469 | call print_string 470 | fatal_error_halt_1: 471 | halt 472 | jr fatal_error_halt_1 473 | 474 | setcolour: ;16-bit colour in bc 475 | push af 476 | ld a, b 477 | out ($06), a 478 | ld a, c 479 | out ($06), a 480 | pop af 481 | ret 482 | 483 | str_console_prompt: 484 | defb 'TeensyZ80> ',0 485 | 486 | file_desc: 487 | defb 'SD:/',0 488 | 489 | readme_desc: 490 | defb 'contents of README.TXT:',0 491 | 492 | str_write_file: 493 | defb 'Writing to TEST.TXT...',0 494 | 495 | str_write_file_OK: 496 | defb 'OK',0 497 | 498 | str_error_file: 499 | defb 'Filesystem error!',0 500 | 501 | str_halt: 502 | defb 'Fatal Error. ',0 503 | 504 | filesys_root_dir_open: 505 | defb 0ffh,0,0,0,0,0,OPEN_READ,'/',0,0,0 ; error byte (init to error), open type byte, filename 8.3, null 506 | 507 | filesys_readme_open_read: 508 | defb 0ffh,0,0,0,0,0,OPEN_READ,'README.TXT',0,0,0 509 | 510 | filesys_test_open_write: 511 | defb 0ffh,0,0,0,0,0,OPEN_WRITE_CREATE,'TEST.TXT',0,0,0,0,0,0 512 | 513 | filesys_speccy_open_read: 514 | defb 0ffh,0,0,0,0,0,OPEN_READ,'SPECCY.565',0,0,0 515 | 516 | filesys_read_request: 517 | ; error, type, offsetlo,offsethi,sizelo,sizehi 518 | defb 0ffh,0,0,0,0,0 519 | defw scratch_mem 520 | 521 | filesys_write_request: 522 | ; error, type, offsetlo,offsethi,sizelo,sizehi 523 | defb 0ffh,1,0,0,8,0 524 | defw test_string 525 | 526 | filesys_speccy_read_req: 527 | ; error, type, offsetlo,offsethi,sizelo,sizehi 528 | defb 0ffh,0,0,0,0,0 529 | defb 0, VRAM_HIGH_BEGIN 530 | 531 | test_string: 532 | defb '0123456',0 533 | 534 | scratch_mem: 535 | 536 | end -------------------------------------------------------------------------------- /z80/multithread_test/kernel.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | // Serial data 5 | __sfr __at 0x01 ioSerialCmd; 6 | __sfr __at 0x02 ioSerialData; 7 | 8 | // Console 9 | __sfr __at 0x03 ioConsolePutChar; 10 | __sfr __at 0x04 ioConsoleRow; 11 | __sfr __at 0x05 ioConsoleCol; 12 | __sfr __at 0x06 ioConsoleColour; 13 | 14 | // VRAM memory mode 15 | __sfr __at 0xC8 ioVRAMBankEnable; 16 | __sfr __banked __at 0x07FFF ioVRAMBankDisable; 17 | 18 | // VRAM facilities - should be disp 19 | __sfr __at 0x07 ioVRAMPaletteOffset; 20 | __sfr __at 0x08 ioVRAMDraw; 21 | __sfr __at 0x09 ioVRAMSetMode; 22 | __sfr __at 0x14 ioDispClear; 23 | 24 | // File System 25 | __sfr __at 0x10 ioFilesysReadWrite; 26 | __sfr __at 0x11 ioFilesysOpenClose; 27 | __sfr __at 0x12 ioFilesysNext; 28 | 29 | __sfr __at 0x64 ioSysRAMSize; 30 | __sfr __at 0x65 ioSysVRAMSize; 31 | 32 | __sfr __at 0x70 ioSysTimeSliceSet; 33 | 34 | unsigned short __at 0x0100 intVectorTable[128]; 35 | 36 | #define COLOUR_BLACK 0x0000 37 | #define COLOUR_BLUE 0x001F 38 | #define COLOUR_RED 0xF800 39 | #define COLOUR_GREEN 0x07E0 40 | #define COLOUR_CYAN 0x07FF 41 | #define COLOUR_MAGENTA 0xF81F 42 | #define COLOUR_YELLOW 0xFFE0 43 | #define COLOUR_WHITE 0xFFFF 44 | 45 | #define SERIAL_CMD_SET_INTVECTOR 0xF1 46 | #define SERIAL_CMD_SET_RATE 0xF2 47 | #define SERIAL_CMD_INIT 0xFA 48 | 49 | #define ASSERT(X) if (!(X)) { __asm di __endasm; con_putStringColoured("ASSERT FAIL: ", COLOUR_RED); con_putString(#X); __asm halt __endasm;} 50 | 51 | 52 | // ZThreading 53 | 54 | #define MAX_THREADS 4 55 | 56 | #define ZTHREAD_HDL_FREE 0 57 | #define ZTHREAD_NOT_STARTED 1 58 | #define ZTHREAD_RUNNING 2 59 | #define ZTHREAD_STOPPED 3 60 | #define ZTHREAD_TERMINATED 4 61 | #define ZTHREAD_EXITED 5 62 | #define ZTHREAD_WAIT_JOIN 6 63 | 64 | 65 | typedef char zthread_t; 66 | typedef int (*startFunc_t) (void*); 67 | 68 | typedef struct internal_context_s { 69 | // we actually save the ctx to the sp 70 | // so we only need the sp to restore all 71 | unsigned short sp; 72 | } internal_context_t; 73 | 74 | typedef struct internal_thread_s { 75 | startFunc_t startFunc; 76 | void* arg; 77 | char flags; 78 | char state_data; 79 | unsigned short stack_start; 80 | internal_context_t ctx; 81 | } internal_thread_t; 82 | 83 | 84 | 85 | #define ZTHREAD_MAX_THREADS_EXCEEDED 0x01 86 | #define ZTHREAD_INVALID_PARAM 0x02 87 | #define ZTHREAD_THREAD_NOT_RUNNING 0x03 88 | 89 | #define DBG_THREADLOG(X) 90 | // thread global state 91 | internal_thread_t threads[MAX_THREADS]; 92 | char num_threads; 93 | char current_thread; 94 | char thread_schedule_counter; 95 | short stackLocationScratch; 96 | 97 | int main( int argc, char* argv[] ); 98 | void con_putString(char* s); 99 | 100 | void con_putChar(char); 101 | void con_setRow (unsigned char); 102 | void con_setCol (unsigned char); 103 | void con_newline(void); 104 | void con_setColour(unsigned short c); 105 | void con_putStringColoured(char* s, unsigned short colour); 106 | 107 | void ihdr_timer_second ( void ) __naked; 108 | void ihdr_timer_timeSlice( void ) __naked; 109 | void ihdr_ignore ( void ) __naked; 110 | 111 | int _TZL_main_start(void* args) ; 112 | 113 | void _TZL_start_threads( void ); 114 | 115 | #define KERNEL_STACK_LOC 0x07F0 116 | 117 | // Always the first function in the compilation unit 118 | void _TZL_start_( void ) __naked { 119 | __asm 120 | ; load the stack pointer to the kernel stack 121 | ld sp, #0x07F0 122 | 123 | __endasm; 124 | 125 | _TZL_start_threads(); 126 | } 127 | 128 | 129 | void SetStack(unsigned short value) __naked { 130 | value; 131 | __asm 132 | pop hl 133 | ld sp, hl 134 | push hl 135 | ret 136 | __endasm; 137 | } 138 | 139 | 140 | 141 | void _TZL_start_threads( void ) { 142 | unsigned char i = 0; 143 | short arg_store[2]; 144 | 145 | con_setRow(0); 146 | con_setCol(0); 147 | 148 | DBG_THREADLOG( con_putString("Setting up interrupt table...");) 149 | 150 | for (; i < 16; i++) { 151 | intVectorTable[i] = (unsigned short)(char*)&ihdr_ignore; 152 | } 153 | 154 | DBG_THREADLOG( con_putString("OK");) 155 | DBG_THREADLOG( con_newline();) 156 | 157 | num_threads = 1; 158 | current_thread = 0; 159 | 160 | DBG_THREADLOG( con_putString("Setting up thread 0...");) 161 | 162 | threads[0].startFunc = _TZL_main_start; 163 | threads[0].arg = &arg_store; 164 | threads[0].flags = ZTHREAD_RUNNING; 165 | threads[0].state_data = 0; 166 | threads[0].stack_start = 0x0400; 167 | 168 | threads[1].flags = ZTHREAD_HDL_FREE; 169 | threads[1].state_data = 0; 170 | threads[1].stack_start = 0x0500; 171 | 172 | threads[2].flags = ZTHREAD_HDL_FREE; 173 | threads[2].state_data = 0; 174 | threads[2].stack_start = 0x0600; 175 | 176 | threads[3].flags = ZTHREAD_HDL_FREE; 177 | threads[3].state_data = 0; 178 | threads[3].stack_start = 0x0700; 179 | 180 | DBG_THREADLOG( con_putString("OK");) 181 | DBG_THREADLOG( con_newline();) 182 | 183 | 184 | DBG_THREADLOG( con_putString("Registering timeslice interrupt...");) 185 | 186 | intVectorTable[3] = (unsigned short)(char*)&ihdr_timer_timeSlice;; 187 | 188 | DBG_THREADLOG( con_putString("OK");) 189 | DBG_THREADLOG( con_newline();) 190 | 191 | { 192 | __asm 193 | im 2 194 | ld a, #0x01 195 | ld i, a 196 | __endasm; 197 | } 198 | 199 | 200 | DBG_THREADLOG( con_putString("Switching stack...");) 201 | // switch to thread 0 202 | //SetStack((unsigned short) threads[0].stack_start-2); 203 | __asm 204 | ; load the stack pointer to the thread0 stack 205 | ld sp, #0x0400 206 | __endasm; 207 | 208 | DBG_THREADLOG( con_putString("OK");) 209 | DBG_THREADLOG( con_newline();) 210 | 211 | DBG_THREADLOG( con_putString("Entering Thread 0.");) 212 | 213 | (*threads[0].startFunc)(threads[0].arg); 214 | 215 | } 216 | 217 | 218 | int _TZL_main_start(void* args) { 219 | void** args_array = (void**)args; 220 | return main((int)args_array[0], (char*[])args_array[1]); 221 | } 222 | 223 | int startFunc_print(void* args) { 224 | char c = (char)args; 225 | while (1) { 226 | con_putChar(c); 227 | } 228 | } 229 | 230 | int zthread_create(zthread_t* handle, startFunc_t startFunc, void* args) { 231 | char this_id = -1; 232 | char idx = 0; 233 | 234 | if ((startFunc == NULL) || (handle == NULL)) { 235 | return ZTHREAD_INVALID_PARAM; 236 | } 237 | 238 | num_threads++; 239 | 240 | // find a free handle 241 | for (; idx < MAX_THREADS; idx++) { 242 | if (threads[idx].flags == ZTHREAD_HDL_FREE) { 243 | this_id = idx; 244 | break; 245 | } 246 | } 247 | 248 | if (this_id <0) { 249 | return ZTHREAD_MAX_THREADS_EXCEEDED; 250 | } 251 | 252 | threads[this_id].startFunc = startFunc; 253 | threads[this_id].arg = args; 254 | threads[this_id].flags = ZTHREAD_NOT_STARTED; 255 | threads[this_id].state_data = 0; 256 | 257 | *handle = this_id; 258 | 259 | return 0; 260 | } 261 | 262 | zthread_t zthread_getThread( void ) { 263 | return (zthread_t)current_thread; 264 | } 265 | 266 | // suspend this thread until the provided thread 267 | // exits. 268 | int zthread_join(zthread_t handle) { 269 | zthread_t thisThread = zthread_getThread(); 270 | if (threads[thisThread].flags != ZTHREAD_RUNNING) { 271 | return ZTHREAD_THREAD_NOT_RUNNING; 272 | } 273 | 274 | // if the thread we want to join with is marked 275 | // as free, assume it's already exited and so 276 | // return. This should be the exited flag, really 277 | if (threads[handle].flags == ZTHREAD_HDL_FREE) { 278 | return 0; 279 | } 280 | 281 | if (threads[handle].flags != ZTHREAD_RUNNING) { 282 | if (threads[handle].flags != ZTHREAD_WAIT_JOIN) { 283 | return ZTHREAD_THREAD_NOT_RUNNING; 284 | } 285 | } 286 | 287 | threads[thisThread].state_data = handle; 288 | threads[thisThread].flags = ZTHREAD_WAIT_JOIN; 289 | 290 | // If other interrupts exist in the system, here we actually need to swap out 291 | // within a critical section 292 | __asm 293 | halt 294 | __endasm; 295 | 296 | return 0; 297 | } 298 | 299 | void _TZL_thread_exited( void ) { 300 | char idx = 0; 301 | zthread_t thisThread = zthread_getThread(); 302 | 303 | // this needs to be in a critical section.. so disable interrupts 304 | __asm 305 | di 306 | __endasm; 307 | 308 | // if any threads are joining to us, tell them they can 309 | // continue now 310 | for (; idx < MAX_THREADS; idx++) { 311 | if ((threads[idx].flags == ZTHREAD_WAIT_JOIN) 312 | && (threads[idx].state_data == thisThread)) { 313 | threads[idx].flags = ZTHREAD_RUNNING; 314 | threads[idx].state_data = 0; 315 | } 316 | } 317 | 318 | // For now, just set the flag as free. 319 | // Really we should set as exited and we can then 320 | // look to get any return value. 321 | threads[thisThread].flags = ZTHREAD_HDL_FREE; 322 | 323 | // this thread ends here. halt so we can be swapped out. 324 | __asm 325 | ei 326 | halt 327 | __endasm; 328 | } 329 | 330 | int zthread_start(zthread_t handle) { 331 | short* stack; 332 | // as writes on the z80 are technically atomic, 333 | // as long as the last write in this function is the 334 | // flags set we do not need to be in a critical section! 335 | threads[handle].ctx.sp = ((unsigned short)threads[handle].stack_start)-18; 336 | stack = (short*)threads[handle].ctx.sp; 337 | stack[0] = 0; // pop iy 338 | stack[1] = 0; // pop ix 339 | stack[2] = 0; // pop de 340 | stack[3] = 0; // pop af 341 | stack[4] = 0; // pop bc 342 | stack[5] = 0; // pop hl 343 | stack[6] = (short)threads[handle].startFunc; 344 | stack[7] = (short)_TZL_thread_exited; 345 | stack[8] = (short)threads[handle].arg; 346 | threads[handle].flags = ZTHREAD_RUNNING; 347 | return 0; 348 | } 349 | 350 | void ihdr_ignore( void ) __naked { 351 | __asm 352 | reti 353 | __endasm; 354 | } 355 | 356 | void ihdr_timer_second( void ) __naked { 357 | __asm 358 | di 359 | __endasm; 360 | con_putString("."); 361 | __asm 362 | ei 363 | reti 364 | __endasm; 365 | } 366 | 367 | void panic_deadlock( void ) { 368 | char buffer[32]; 369 | char idx = 0; 370 | ioDispClear = 0; 371 | con_setCol(8); 372 | con_setRow(2); 373 | con_putStringColoured("*** DEADLOCK DETECTED ***", COLOUR_RED); 374 | con_setCol(8); 375 | con_setRow(3); 376 | con_putStringColoured("=========================", COLOUR_YELLOW); 377 | con_setCol(0); 378 | con_setRow(5); 379 | con_putStringColoured("NO THREADS IN A STATE TO RUN", COLOUR_WHITE); 380 | con_newline(); 381 | con_newline(); 382 | con_putString(" IDX FLAGS STATE"); 383 | con_newline(); 384 | con_putString(" ===================="); 385 | con_newline(); 386 | for (idx=0; idx= MAX_THREADS) { 425 | current_thread = 0; 426 | } 427 | } while ((threads[current_thread].flags != ZTHREAD_RUNNING) 428 | && (thread_schedule_counter <= MAX_THREADS)); 429 | 430 | if (thread_schedule_counter > MAX_THREADS) { 431 | // swap to the kernel stack for this 432 | __asm 433 | ; load the stack pointer to the kernel stack 434 | ld sp, #0x07F0 435 | __endasm; 436 | 437 | panic_deadlock(); 438 | } 439 | 440 | // load stack of next thread ctx 441 | stackLocationScratch = threads[current_thread].ctx.sp; 442 | 443 | // restore registers 444 | __asm 445 | ex af, af' 446 | exx 447 | ld sp, (_stackLocationScratch) 448 | pop iy 449 | pop ix 450 | pop de 451 | pop af 452 | pop bc 453 | pop hl 454 | ei 455 | reti 456 | __endasm; 457 | 458 | } 459 | 460 | void serial_setIntVector( unsigned char vector ) { 461 | ioSerialCmd = SERIAL_CMD_SET_INTVECTOR; 462 | ioSerialCmd = vector; 463 | } 464 | 465 | void serial_setRate(short rate) { 466 | ioSerialCmd = SERIAL_CMD_SET_RATE; 467 | ioSerialCmd = (unsigned char)(rate & 0xFF); 468 | ioSerialCmd = (unsigned char)(rate >> 8U); 469 | } 470 | 471 | void serial_init( void ) { 472 | ioSerialCmd = SERIAL_CMD_INIT; 473 | } 474 | 475 | char serial_avail( void ) { 476 | return ioSerialCmd; 477 | } 478 | 479 | char serial_getChar( void ) { 480 | while (!ioSerialCmd); 481 | return ioSerialData; 482 | } 483 | 484 | void serial_putChar( char c ) { 485 | ioSerialData = c; 486 | } 487 | 488 | void disp_enableVRAMWrite() { 489 | __asm 490 | di 491 | __endasm; 492 | ioVRAMBankEnable = 0; 493 | } 494 | 495 | void disp_disableVRAMWrite() { 496 | char c = ioVRAMBankDisable; 497 | __asm 498 | ei 499 | __endasm; 500 | } 501 | 502 | enum displayMode_e { 503 | mode48x48x16 = 0, 504 | mode48x48x8P, 505 | mode48x48x8PStretch, 506 | mode160x120x8P, 507 | mode160x120x8PStretch, 508 | mode40x30x16Stretch, 509 | mode80x60x8PStretch, 510 | mode80x60x8P, 511 | }; 512 | 513 | void disp_setMode(enum displayMode_e mode) { 514 | ioVRAMSetMode = (unsigned char)mode; 515 | } 516 | 517 | void disp_draw( void ) { 518 | ioVRAMDraw = 0; 519 | } 520 | 521 | void disp_clear( void ) { 522 | ioDispClear = 0; 523 | } 524 | 525 | short sys_getRAMSize(void) { 526 | return (ioSysRAMSize<<8U); 527 | } 528 | 529 | short sys_getVRAMSize(void) { 530 | return (ioSysVRAMSize<<8U); 531 | } 532 | 533 | void con_putChar(char c) { 534 | ioConsolePutChar = c; 535 | } 536 | 537 | void con_putString(char* s) { 538 | while (*s) { 539 | con_putChar(*s); 540 | s++; 541 | } 542 | } 543 | 544 | void con_setRow(unsigned char r) { 545 | ioConsoleRow = r; 546 | } 547 | 548 | unsigned char con_getRow(void) { 549 | return ioConsoleRow; 550 | } 551 | 552 | void con_setCol(unsigned char c) { 553 | ioConsoleCol = c; 554 | } 555 | 556 | unsigned char con_getCol(void) { 557 | return ioConsoleCol; 558 | } 559 | 560 | void con_newline(void) { 561 | unsigned char row = con_getRow(); 562 | row++; 563 | con_setRow(row); 564 | con_setCol(0); 565 | } 566 | 567 | void con_newlines(unsigned char num) { 568 | for (; num>0; num--) { 569 | con_newline(); 570 | } 571 | } 572 | 573 | void con_setColour(unsigned short c) { 574 | ioConsoleColour = (unsigned char)(c & 0xFF); 575 | ioConsoleColour = (unsigned char)(c >> 8U); 576 | } 577 | 578 | void con_putStringColoured(char* s, unsigned short colour) { 579 | con_setColour(colour); 580 | con_putString(s); 581 | } 582 | 583 | int startFunc_print2(void* args) { 584 | char c = (char)args; 585 | short num = 400; 586 | while (num--) { 587 | con_putChar(c); 588 | } 589 | return 0; 590 | } 591 | 592 | int startFunc_print_deadlock(void* args) { 593 | char c = (char)args; 594 | char num = 140; 595 | while (num--) { 596 | con_putChar(c); 597 | } 598 | 599 | // main thread always id 0 600 | ASSERT(! zthread_join(0)); 601 | return 0; 602 | } 603 | 604 | 605 | int main( int argc, char* argv[] ) { 606 | 607 | zthread_t threadA; 608 | zthread_t threadB; 609 | zthread_t threadC; 610 | 611 | argc; 612 | argv; 613 | 614 | ASSERT(! zthread_create(&threadA, startFunc_print2, (char*)(short)'A')); 615 | ASSERT(! zthread_create(&threadB, startFunc_print2, (char*)(short)'B')); 616 | ASSERT(! zthread_create(&threadC, startFunc_print2, (char*)(short)'C')); 617 | 618 | ASSERT(! zthread_start(threadA)); 619 | ASSERT(! zthread_start(threadB)); 620 | ASSERT(! zthread_start(threadC)); 621 | 622 | __asm 623 | ei 624 | __endasm; 625 | 626 | 627 | ASSERT(! zthread_join(threadA)); 628 | 629 | ASSERT(! zthread_join(threadB)); 630 | 631 | ASSERT(! zthread_join(threadC)); 632 | 633 | con_putString(" Thread A,B & C has exited, main thread can continue to deadlock detection test! "); 634 | 635 | ASSERT(! zthread_create(&threadA, startFunc_print_deadlock, (char*)(short)'!')); 636 | ASSERT(! zthread_start(threadA)); 637 | 638 | startFunc_print2((char*)(short)'P'); 639 | 640 | ASSERT(! zthread_join(threadA)); 641 | 642 | while(1) { 643 | con_putChar('M'); 644 | } 645 | 646 | return 0; 647 | } 648 | 649 | 650 | 651 | 652 | 653 | -------------------------------------------------------------------------------- /Teensy31/z80controller.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * TeensyZ80 by Colin "Domipheus" Riley 3 | * 4 | * This implements a Clock, RAM/ROM, Serial Device, Console Output, 5 | * and Mode 2 Interrupts. There is a 16KB global array which should 6 | * be initialized to the 'ROM', but in essence this is all ram and 7 | * the whole 16KB is read/writable. The Serial device and Console 8 | * is implemented via I/O ports. 9 | * 10 | * This is intended for educational purposes - it is fully in-sync, 11 | * in that everything occurs in a clock. The Z80 is clocked fully 12 | * in step with operations in the loop() functions and as such the 13 | * Z80 WAIT line is not required. This has the side effect of being 14 | * fairly slow, but at ~60KHz is responsive enough to run some 15 | * programs. 16 | * 17 | * This code is in flux, so may have unfinished features etc. 18 | * 19 | * ================================================================ 20 | */ 21 | #include 22 | #include 23 | 24 | /* 25 | * SPI pin definitions 26 | * Don't change! First block is the TFT pins. 27 | * Second block is for SD card chip select. Bus shared. 28 | * ======================================================= 29 | */ 30 | #include 31 | #define sclk 13 32 | #define mosi 11 33 | #define miso 12 34 | #define cs 10 35 | #define dc 9 36 | 37 | 38 | #include 39 | #define sdcs 8 40 | 41 | /* 42 | * Z80 pin definitions 43 | * Some analog pins exist here, so the read functions are different 44 | * ================================================================ 45 | */ 46 | #define Z_CLK 29 47 | 48 | #define AD0 23 49 | #define AD1 22 50 | #define AD2 21 51 | #define AD3 20 52 | #define AD4 19 53 | #define AD5 18 54 | #define AD6 17 55 | #define AD7 16 56 | #define AD8 15 57 | #define AD9 14 58 | #define AD10 30 59 | #define AD11 A12 60 | #define AD12 A11 61 | #define AD13 A13 62 | #define AD14 A14 63 | #define AD15 64 | 65 | #define D0 1 66 | #define D1 0 67 | #define D2 3 68 | #define D3 6 69 | #define D4 7 70 | #define D5 5 71 | #define D6 4 72 | #define D7 2 73 | 74 | #define WR 28 75 | #define RD 25 76 | #define M1 32 77 | #define MREQ 31 78 | #define IOREQ 24 79 | #define RFSH 27 80 | #define RESET 26 81 | #define INT 33 82 | 83 | /* 84 | * SPI TFT LCD 2.2" 320x240 85 | * ============================ 86 | */ 87 | ILI9341_t3 tft = ILI9341_t3(cs, dc); 88 | 89 | //file auto-generated from sd_error.565 by bin2h.exe 90 | size_t IMG_sd_error_len = 2400; 91 | unsigned char IMG_sd_error[2400]= 92 | { 93 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 94 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 95 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 96 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 97 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 98 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 99 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 100 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 101 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 102 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 103 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 104 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 105 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 106 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 107 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 108 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x00,0xF8, 109 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF, 110 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 111 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, 112 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 113 | 0x00,0x00,0x00,0x00,0x00,0xF8,0x00,0xF8,0x00,0x00,0x00, 114 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 115 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 116 | 0xF8,0x00,0xF8,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00, 117 | 0xFF,0xFF,0x3F,0x00,0x3F,0x00,0x3F,0x00,0x3F,0x00,0x3F, 118 | 0x00,0x3F,0x00,0x3F,0x00,0x3F,0x00,0x3F,0x00,0x3F,0x00, 119 | 0x3F,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 120 | 0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x00,0xF8,0x00,0xF8, 121 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 122 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 123 | 0x00,0x00,0x00,0x00,0x00,0xF8,0x00,0xF8,0x00,0xF8,0x00, 124 | 0x00,0x00,0x00,0xFF,0xFF,0x3F,0x00,0x3F,0x00,0x3F,0x00, 125 | 0x3F,0x00,0x3F,0x00,0x3F,0x00,0x3F,0x00,0x3F,0x00,0x3F, 126 | 0x00,0x3F,0x00,0x3F,0x00,0x3F,0x00,0xFF,0xFF,0x00,0x00, 127 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x00,0xF8,0x00, 128 | 0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 129 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 130 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8, 131 | 0x00,0xF8,0x00,0xF8,0x00,0x00,0xFF,0xFF,0x3F,0x00,0x3F, 132 | 0x00,0x3F,0x00,0x3F,0x00,0x3F,0x00,0x3F,0x00,0x3F,0x00, 133 | 0x3F,0x00,0x3F,0x00,0x3F,0x00,0x3F,0x00,0x3F,0x00,0x3F, 134 | 0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0xF8,0x00,0xF8, 135 | 0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 136 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 137 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 138 | 0x00,0x00,0x00,0x00,0xF8,0x00,0xF8,0x00,0x00,0xFF,0xFF, 139 | 0x3F,0x00,0x3F,0x00,0x00,0xF8,0x00,0xF8,0x00,0xF8,0x00, 140 | 0xF8,0x00,0xF8,0x00,0xF8,0x00,0xF8,0x00,0xF8,0x00,0xF8, 141 | 0x00,0xF8,0x3F,0x00,0x3F,0x00,0xFF,0xFF,0x00,0x00,0x00, 142 | 0xF8,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 143 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 144 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 145 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x00, 146 | 0x00,0xFF,0xFF,0x3F,0x00,0x3F,0x00,0x00,0xF8,0xFF,0xFF, 147 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 148 | 0xFF,0xFF,0xFF,0x00,0xF8,0x3F,0x00,0x3F,0x00,0xFF,0xFF, 149 | 0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 150 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 151 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 152 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 153 | 0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x3F,0x00,0x00, 154 | 0xF8,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00, 155 | 0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0xF8,0x3F,0x00,0xFF, 156 | 0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 157 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 158 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 159 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 160 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF, 161 | 0x3F,0x00,0x00,0xF8,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00, 162 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0xF8, 163 | 0x3F,0x00,0x3F,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00, 164 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 165 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 166 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 167 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 168 | 0x00,0xFF,0xFF,0x3F,0x00,0x00,0xF8,0xFF,0xFF,0x00,0x00, 169 | 0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF, 170 | 0xFF,0x00,0xF8,0x3F,0x00,0x3F,0x00,0xFF,0xFF,0x00,0x00, 171 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 172 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 173 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 174 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 175 | 0x00,0x00,0x00,0x00,0xFF,0xFF,0x3F,0x00,0x00,0xF8,0xFF, 176 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00, 177 | 0x00,0x00,0xFF,0xFF,0x00,0xF8,0x3F,0x00,0x3F,0x00,0xFF, 178 | 0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 179 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 180 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 181 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 182 | 0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x3F,0x00,0x3F,0x00, 183 | 0x00,0xF8,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, 184 | 0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0xF8,0x3F,0x00, 185 | 0x3F,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 186 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 187 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 188 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 189 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x3F, 190 | 0x00,0x3F,0x00,0x00,0xF8,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 191 | 0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, 192 | 0xF8,0x3F,0x00,0x3F,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00, 193 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 194 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 195 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 196 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 197 | 0xFF,0xFF,0x3F,0x00,0x3F,0x00,0x00,0xF8,0xFF,0xFF,0xFF, 198 | 0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF, 199 | 0xFF,0xFF,0x00,0xF8,0x3F,0x00,0x3F,0x00,0xFF,0xFF,0x00, 200 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 201 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 202 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 203 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 204 | 0x00,0x00,0x00,0xFF,0xFF,0x3F,0x00,0x3F,0x00,0x00,0xF8, 205 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF, 206 | 0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0xF8,0x3F,0x00,0x3F,0x00, 207 | 0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 208 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 209 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 210 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 211 | 0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x3F,0x00,0x3F, 212 | 0x00,0x00,0xF8,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 213 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0xF8,0x3F, 214 | 0x00,0x3F,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00, 215 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 216 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 217 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 218 | 0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x00,0x00,0xFF,0xFF, 219 | 0x3F,0x00,0x3F,0x00,0x00,0xF8,0xFF,0xFF,0xFF,0xFF,0xFF, 220 | 0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 221 | 0x00,0xF8,0x3F,0x00,0x3F,0x00,0xFF,0xFF,0x00,0x00,0x00, 222 | 0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 223 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 224 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 225 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x00,0xF8,0x00, 226 | 0x00,0xFF,0xFF,0x3F,0x00,0x3F,0x00,0x00,0xF8,0xFF,0xFF, 227 | 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF, 228 | 0xFF,0xFF,0xFF,0x00,0xF8,0x3F,0x00,0x3F,0x00,0xFF,0xFF, 229 | 0x00,0x00,0x00,0xF8,0x00,0xF8,0x00,0x00,0x00,0x00,0x00, 230 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 231 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 232 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x00,0xF8, 233 | 0x00,0xF8,0x00,0x00,0xFF,0xFF,0x3F,0x00,0x3F,0x00,0x00, 234 | 0xF8,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 235 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0xF8,0x3F,0x00,0x3F, 236 | 0x00,0xFF,0xFF,0x00,0x00,0x00,0xF8,0x00,0xF8,0x00,0xF8, 237 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 238 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 239 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x00, 240 | 0xF8,0x00,0xF8,0x00,0x00,0x00,0x00,0xFF,0xFF,0x3F,0x00, 241 | 0x3F,0x00,0x00,0xF8,0x00,0xF8,0x00,0xF8,0x00,0xF8,0x00, 242 | 0xF8,0x00,0xF8,0x00,0xF8,0x00,0xF8,0x00,0xF8,0x00,0xF8, 243 | 0x3F,0x00,0x3F,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00, 244 | 0xF8,0x00,0xF8,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00, 245 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 246 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8, 247 | 0x00,0xF8,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0xFF, 248 | 0xFF,0x3F,0x00,0x3F,0x00,0x3F,0x00,0x3F,0x00,0x3F,0x00, 249 | 0x3F,0x00,0x3F,0x00,0x3F,0x00,0x3F,0x00,0x3F,0x00,0x3F, 250 | 0x00,0x3F,0x00,0x3F,0x00,0x3F,0x00,0xFF,0xFF,0x00,0x00, 251 | 0x00,0x00,0x00,0x00,0x00,0xF8,0x00,0xF8,0x00,0xF8,0x00, 252 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 253 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 254 | 0x00,0x00,0xF8,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00, 255 | 0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 256 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 257 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 258 | 0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8, 259 | 0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 260 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 261 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 262 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 263 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 264 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 265 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 266 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 267 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 268 | 0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00, 269 | 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 270 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF, 271 | 0xFF,0xFF,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00, 272 | 0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00, 273 | 0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00, 274 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 275 | 0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00, 276 | 0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0x00,0x00, 277 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF, 278 | 0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00, 279 | 0xFF,0xFF,0x00,0x00,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0x00, 280 | 0x00,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0x00,0x00,0xFF,0xFF, 281 | 0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 282 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF, 283 | 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0x00,0x00,0xFF, 284 | 0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 285 | 0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF, 286 | 0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF, 287 | 0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0x00, 288 | 0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00, 289 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 290 | 0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0xFF,0xFF, 291 | 0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 292 | 0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00, 293 | 0x00,0x00,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0x00,0x00,0xFF, 294 | 0xFF,0x00,0x00,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0x00,0x00, 295 | 0xFF,0xFF,0x00,0x00,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0x00, 296 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 297 | 0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00, 298 | 0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00, 299 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF, 300 | 0xFF,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0x00,0x00,0xFF,0xFF, 301 | 0x00,0x00,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00, 302 | 0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00, 303 | 0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 304 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 305 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 306 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 307 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 308 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 309 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 310 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 311 | 0x00,0x00, 312 | }; 313 | 314 | /* 315 | * 20KB VRAM 316 | * ========= 317 | */ 318 | #define Z80_VRAM_LENGTH 0x5000 319 | byte Z80_VRAM[Z80_VRAM_LENGTH] = {0}; 320 | 321 | 322 | /* 323 | * 32KB RAM (there is no rom) 324 | * ============================ 325 | */ 326 | #define Z80_RAM_LENGTH 0x7000 327 | unsigned char Z80_RAM [Z80_RAM_LENGTH]= 328 | { 329 | 0xF3,0x31,0xF0,0x07,0xED,0x5E,0x3E,0x01,0xED,0x47,0xC3, 330 | 0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 331 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 332 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 333 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 334 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 335 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 336 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 337 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 338 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 339 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 340 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 341 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 342 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 343 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 344 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 345 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 346 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 347 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 348 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 349 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 350 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 351 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 352 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 353 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 354 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 355 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 356 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 357 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 358 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 359 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 360 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 361 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 362 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 363 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 364 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 365 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 366 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 367 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 368 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 369 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 370 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 371 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 372 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 373 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 374 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 375 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 376 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 377 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 378 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 379 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 380 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 381 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 382 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 383 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 384 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 385 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 386 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 387 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 388 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 389 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 390 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 391 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 392 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 393 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 394 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 395 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 396 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 397 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 398 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 399 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 400 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 401 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 402 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 403 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 404 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 405 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 406 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 407 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 408 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 409 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 410 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 411 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 412 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 413 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 414 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 415 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 416 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 417 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 418 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 419 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 420 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 421 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 422 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 423 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 424 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 425 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 426 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 427 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 428 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 429 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 430 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 431 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 432 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 433 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 434 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 435 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 436 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 437 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 438 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 439 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 440 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 441 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 442 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 443 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 444 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 445 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 446 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 447 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 448 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 449 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 450 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 451 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 452 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 453 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 454 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 455 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 456 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 457 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 458 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 459 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 460 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 461 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 462 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 463 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 464 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 465 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 466 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 467 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 468 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 469 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 470 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 471 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 472 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 473 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 474 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 475 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 476 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 477 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 478 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 479 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 480 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 481 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 482 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 483 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 484 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 485 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 486 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 487 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 488 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 489 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 490 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 491 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 492 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 493 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 494 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 495 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 496 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 497 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 498 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 499 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 500 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 501 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 502 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 503 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 504 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 505 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 506 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 507 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 508 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 509 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 510 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 511 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 512 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 513 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 514 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 515 | 0x00,0x00,0x3E,0x00,0xD3,0x04,0xD3,0x05,0x3E,0x3F,0xD3, 516 | 0x03,0x76, 517 | 518 | /* unthradded boot 519 | 0xF3,0xDB,0x64,0x67,0x2E,0x00,0xF9,0xED,0x5E,0x3E,0x01, 520 | 0xED,0x47,0xC3,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00, 521 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 522 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 523 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 524 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 525 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 526 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 527 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 528 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 529 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 530 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 531 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 532 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 533 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 534 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 535 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 536 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 537 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 538 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 539 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 540 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 541 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 542 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 543 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 544 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 545 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 546 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 547 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 548 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 549 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 550 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 551 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 552 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 553 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 554 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 555 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 556 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 557 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 558 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 559 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 560 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 561 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 562 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 563 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 564 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 565 | 0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0xD3,0x04,0xD3, 566 | 0x05,0x3E,0x3F,0xD3,0x03,0x76,*/ 567 | }; 568 | 569 | /* 570 | * Signals/Buses from CPU 571 | * ====================== 572 | */ 573 | byte M1_val = 0; 574 | byte RFSH_val = 0; 575 | byte RD_val = 0; 576 | byte WR_val = 0; 577 | byte MEMREQ_val = 0; 578 | byte IOREQ_val = 0; 579 | unsigned short addressBus = 0; 580 | unsigned char dataBus = 0; 581 | 582 | 583 | /* 584 | * Console/Terminal Definitions 585 | * ============================ 586 | */ 587 | #define CONSOLE_FONTY 9 588 | #define CONSOLE_FONTX 7 589 | #define CONSOLE_START_Y 10 590 | #define CONSOLE_START_X 10 591 | #define CONSOLE_ROWS 24 592 | #define CONSOLE_COLUMNS 42 593 | 594 | byte console_current_row = 0; 595 | byte console_current_col = 0; 596 | unsigned short console_current_color = 0xFFFF; 597 | byte console_current_color_state = 0; 598 | 599 | /* 600 | * Vram Emulation Definitions 601 | * ============================ 602 | */ 603 | unsigned short ioVramBuffer = 0; 604 | 605 | uint8_t ioVramWidth = 64; 606 | uint8_t ioVramHeight = 64; 607 | 608 | uint8_t ioVramDisplayMode = 1; 609 | uint8_t ioVramBankSet = 0; 610 | uint8_t ioVramPaletteIdx = 0; 611 | 612 | /* 613 | * Display Mode Definitions 614 | * ============================ 615 | * 616 | * How to interpret mode layout in mem: 617 | * 618 | * ADR RANGE, DESC 619 | * --------------- 620 | * 0x0 to n=((2^bpp)*(palette_bpp/8)) - Colour pallete 621 | * n to 0x5000 - Pixel data 622 | */ 623 | typedef struct displayModes_s { 624 | uint16_t width; 625 | uint16_t height; 626 | uint8_t bpp; 627 | uint8_t palette_bpp; 628 | uint8_t stretch; 629 | uint8_t reserved1; 630 | uint8_t reserved2; 631 | uint8_t reserved3; 632 | } displayMode_t; 633 | 634 | displayMode_t displayModeTable[] = { 635 | {48, 48, 16, 0, 0, 0,0,0}, //0 636 | {48, 48, 8, 16, 0, 0,0,0}, //1 637 | {48, 48, 8, 16, 1, 0,0,0}, //2 638 | {160, 120, 8, 16, 0, 0,0,0}, //3 639 | {160, 120, 8, 16, 1, 0,0,0}, //4 640 | {40, 30, 16, 0, 1, 0,0,0}, //5 - default for errors 641 | {80, 60, 8, 16, 1, 0,0,0}, //6 642 | {80, 60, 8, 16, 0, 0,0,0}, //7 643 | }; 644 | 645 | #define DISPLAY_MODE_MAX 7 646 | 647 | 648 | 649 | 650 | 651 | 652 | /* 653 | * I/O Port Definitions 654 | * ============================ 655 | */ 656 | #define PORT_SERIAL_CMD 1 657 | #define PORT_SERIAL_DATA 2 658 | #define PORT_DISP_PUTCHAR 3 659 | #define PORT_DISP_SETROW 4 660 | #define PORT_DISP_SETCOL 5 661 | #define PORT_DISP_SETCOLOUR 6 662 | 663 | #define PORT_RAM_BANK_SET 0xC8 664 | #define PORT_DISP_CLEAR 20 665 | 666 | // this should be (PORT_VRAM_SIZE-1U)? 667 | #define PORT_RAM_BANK_RESET 0x7FFF 668 | 669 | #define PORT_VRAM_BUFFER_LOC 0 670 | #define PORT_VRAM_PALETTE_IDX 7 671 | #define PORT_VRAM_DRAW 8 672 | #define PORT_VRAM_SETMODE 9 673 | 674 | #define PORT_RAM_SIZE 100 675 | #define PORT_VRAM_SIZE 101 676 | 677 | #define PORT_FILESYS_READ_WRITE 10 678 | #define PORT_FILESYS_OPEN 11 679 | #define PORT_FILESYS_NEXT 12 680 | 681 | 682 | /* 683 | * Serial Communications Device 684 | * ============================ 685 | */ 686 | #define SERIAL_CMD_SET_INTVECTOR 0xF1 687 | #define SERIAL_CMD_SET_RATE 0xF2 688 | #define SERIAL_CMD_INIT 0xFA 689 | 690 | // The set rate command takes a 16 bit value (For now) which means it 691 | // needs multiple cycles/io writes to complete 692 | #define SERIAL_CMD_SET_RATE_2 0x02 693 | #define SERIAL_CMD_READY 0 694 | 695 | //State info needs to understand the IO timings as the commands can remain on the buses 696 | // for many cycles 697 | int ioDebounce = 0; 698 | 699 | unsigned short ioSerialIntVector = 0; 700 | int ioSerialInitialized = 0; 701 | unsigned short ioSerialRate = 0; 702 | int ioSerialCurrentMode = SERIAL_CMD_READY; 703 | 704 | // We dont want to constantly be flagging interupts. Only flag it if weve completed the 705 | // previous one 706 | int ioSerialINTDebounce = 0; 707 | 708 | 709 | byte currentInterruptVector = 0; 710 | int currentInterrupt = 0; 711 | 712 | 713 | 714 | /* 715 | * Debug Display Options 716 | * ===================== 717 | */ 718 | #define MEMORY_DISPLAY 0 719 | #define VRAM_DISPLAY 0 720 | #define DBG_DRAW_DATA 0 721 | #define DBG_DRAW_ADDR 0 722 | #define DBG_DRAW_CYCLE 0 723 | #define DBG_DRAW_LOG 0 724 | #define DBG_DRAW_LOG_DELAY 70 725 | 726 | /* 727 | * Debug Log definitions 728 | * ============================ 729 | */ 730 | #define GFX_ADDR_START 15 731 | #define GFX_DATA_START 35 732 | #define GFX_CONTROL_START 55 733 | #define GFX_LOG_START 50 734 | #define GFX_LOG_LINES 26 735 | int current_line = 0; 736 | 737 | 738 | #define DELAY 20 739 | unsigned int cycle = 0; 740 | 741 | 742 | /* 743 | * SD Card File System Device 744 | * ============================ 745 | */ 746 | #define FILESYS_RW_READY 1 747 | #define FILESYS_RW_EXEC 13 748 | #define FILESYS_RW_SETCMDMEMPTR 2 749 | #define FILESYS_RW_SETCMDMEMPTR_2 3 750 | 751 | #define FILESYS_OPEN_READY 4 752 | #define FILESYS_OPEN_OPENFILE 5 753 | #define FILESYS_OPEN_SETMEMPTR 6 754 | #define FILESYS_OPEN_SETMEMPTR_2 7 755 | 756 | #define FILESYS_NEXT_READY 8 757 | #define FILESYS_NEXT_GETNEXT 9 758 | #define FILESYS_NEXT_SETMEMPTR 10 759 | #define FILESYS_NEXT_SETMEMPTR_2 11 760 | 761 | #define FILESYS_CLOSE_FILE 12 762 | 763 | #define OPEN_READ 0 764 | #define OPEN_WRITE 1 765 | #define OPEN_WRITE_CREATE 2 766 | #define OPEN_APPEND 3 767 | #define OPEN_RDWR 4 768 | 769 | Sd2Card card; 770 | SdVolume volume; 771 | SdFile ioFileSysCWD; 772 | SdFile ioFileSysCurrentFile; 773 | 774 | byte ioFileSysRWCurrentMode = FILESYS_RW_READY; 775 | unsigned short ioFileSysRWCmdMemPtr = 0; 776 | 777 | byte ioFileSysOpenCurrentMode = FILESYS_OPEN_READY; 778 | unsigned short ioFileSysOpenMemPtr = 0; 779 | 780 | byte ioFileSysNextCurrentMode = FILESYS_NEXT_READY; 781 | unsigned short ioFileSysNextMemPtr = 0; 782 | 783 | 784 | 785 | // Helper function 786 | char* fmtstring(char *fmt, ... ) 787 | { 788 | static char tmp[256]; 789 | va_list args; 790 | va_start (args, fmt ); 791 | vsnprintf(tmp, 256, fmt, args); 792 | va_end (args); 793 | return &tmp[0]; 794 | } 795 | 796 | void performZ80Reset() 797 | { 798 | //Perform a reset for 4 cycles (manual says 3 should be enough). 799 | digitalWrite(RESET, LOW); 800 | for (int i = 0; i<8; i++) 801 | { 802 | digitalWrite(Z_CLK, HIGH); 803 | delay(1); 804 | digitalWrite(Z_CLK, LOW); 805 | delay(1); 806 | } 807 | //bring CPU out of reset state 808 | digitalWrite(RESET, HIGH); 809 | } 810 | 811 | void updateZ80Control() 812 | { 813 | M1_val = digitalRead(M1)==LOW?1:0; 814 | RFSH_val = digitalRead(RFSH)==LOW?1:0; 815 | RD_val = digitalRead(RD)==LOW?1:0; 816 | WR_val = digitalRead(WR)==LOW?1:0; 817 | MEMREQ_val = digitalRead(MREQ)==LOW?1:0; 818 | IOREQ_val = digitalRead(IOREQ)==LOW?1:0; 819 | } 820 | 821 | void vramDraw() 822 | { 823 | uint16_t w = displayModeTable[ioVramDisplayMode].width; 824 | uint16_t h = displayModeTable[ioVramDisplayMode].height; 825 | uint8_t bpp = displayModeTable[ioVramDisplayMode].bpp; 826 | uint8_t palette_bpp = displayModeTable[ioVramDisplayMode].palette_bpp; 827 | uint8_t stretch = displayModeTable[ioVramDisplayMode].stretch; 828 | 829 | uint8_t px_w = displayModeTable[ioVramDisplayMode].reserved2; 830 | uint8_t px_h = displayModeTable[ioVramDisplayMode].reserved3; 831 | 832 | uint8_t* pixel8 = (uint8_t*)&Z80_VRAM[0x200]; 833 | uint16_t* pixel16 = (uint16_t*)&Z80_VRAM[0x200]; 834 | 835 | uint16_t* palette = (uint16_t*)&Z80_VRAM[0]; 836 | 837 | if (palette_bpp == 0) 838 | { 839 | pixel16 = (uint16_t*)palette; 840 | pixel8 = (uint8_t*)palette; 841 | } 842 | 843 | int native_res_x = 320; 844 | int native_res_y = 240; 845 | 846 | int scrOffsetX = 0; 847 | int scrOffsetY = 0; 848 | 849 | if (stretch) 850 | { 851 | if (px_w == 0) 852 | { 853 | // calculate pixel width/height 854 | px_w = (uint8_t)((float)native_res_x/(float)w); 855 | px_h = (uint8_t)((float)native_res_y/(float)h); 856 | // cache values 857 | displayModeTable[ioVramDisplayMode].reserved2 = px_w; 858 | displayModeTable[ioVramDisplayMode].reserved3 = px_h; 859 | } 860 | 861 | int stretch_h = px_h * h; 862 | int stretch_w = px_w * w; 863 | 864 | 865 | for (int y = 0, py = 0; y < stretch_h; y+= px_h, py++) 866 | { 867 | for (int x = 0, px = 0; x < stretch_w; x+= px_w, px++) 868 | { 869 | tft.fillRect (x, y, px_w, px_h, 870 | (palette_bpp != 0) 871 | ? palette[ (ioVramPaletteIdx + pixel8[py*w+px])&0xff ] 872 | : pixel16[py*w+px]); 873 | } 874 | } 875 | 876 | } 877 | else 878 | { 879 | scrOffsetX = (int)((native_res_x-w)/2.0f); 880 | scrOffsetY = (int)((native_res_y-h)/2.0f); 881 | 882 | for (int y = 0; y < h; y++) 883 | { 884 | for (int x = 0; x < w; x++) 885 | { 886 | tft.drawPixel(scrOffsetX + x, scrOffsetY + y, 887 | (palette_bpp != 0) 888 | ? palette[ (ioVramPaletteIdx + pixel8[y*w+x])&0xff ] 889 | : pixel16[y*w+x]); 890 | } 891 | } 892 | } 893 | } 894 | 895 | int hardHalt = 0; 896 | 897 | void setup(void) { 898 | 899 | Serial.begin(9600); 900 | tft.begin(); 901 | 902 | tft.setRotation(1); // 0 - Portrait, 1 - Lanscape 903 | tft.fillScreen(ILI9341_BLACK); 904 | tft.setTextColor(ILI9341_WHITE,ILI9341_BLACK); 905 | tft.setTextWrap(true); 906 | 907 | // delay(10); 908 | 909 | // Test starting the SD card 910 | // We dont do anything else with it just now. May need 911 | // to ensure the SPI commands are working after the tft 912 | // is used after this code. 913 | pinMode(sdcs, OUTPUT); 914 | if (!card.init(SPI_HALF_SPEED, sdcs)) 915 | { 916 | //tft.setCursor (20, 20); 917 | //tft.println("Card failed, or not present"); 918 | // don't do anything more: 919 | ioVramDisplayMode = 5; 920 | // copy sd error image to vram 921 | memcpy(&Z80_VRAM[0], &IMG_sd_error[0], IMG_sd_error_len); 922 | 923 | vramDraw(); 924 | hardHalt = 1; 925 | //return; 926 | } 927 | else 928 | { 929 | 930 | // tft.setCursor (20, 20); 931 | // tft.println("SD Card OK"); 932 | 933 | // Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32 934 | if (!volume.init(card)) 935 | { 936 | tft.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card"); 937 | } 938 | else 939 | { 940 | // print the type and size of the first FAT-type volume 941 | uint32_t volumesize; 942 | // tft.print("\nVolume type is FAT"); 943 | // tft.println(volume.fatType(), DEC); 944 | // tft.println(); 945 | 946 | volumesize = volume.blocksPerCluster(); // clusters are collections of blocks 947 | volumesize *= volume.clusterCount(); // we'll have a lot of clusters 948 | volumesize *= 512; // SD card blocks are always 512 bytes 949 | // tft.print("Volume size (bytes): "); 950 | // tft.println(volumesize); 951 | // tft.print("Volume size (Kbytes): "); 952 | volumesize /= 1024; 953 | // tft.println(volumesize); 954 | // tft.print("Volume size (Mbytes): "); 955 | // volumesize /= 1024; 956 | // tft.println(volumesize); 957 | 958 | // Load the kernel into 0x200 959 | 960 | SdFile rootdir; 961 | rootdir.openRoot(volume); 962 | SdFile kernelbin; 963 | kernelbin.open( rootdir, "kernel.bin", O_READ); 964 | 965 | if (kernelbin.isOpen()) { 966 | kernelbin.read(&Z80_RAM[0x800], kernelbin.fileSize()); 967 | kernelbin.close(); 968 | } 969 | 970 | rootdir.close(); 971 | 972 | } 973 | } 974 | 975 | //Address bus always input 976 | pinMode(AD0, INPUT); 977 | pinMode(AD1, INPUT); 978 | pinMode(AD2, INPUT); 979 | pinMode(AD3, INPUT); 980 | pinMode(AD4, INPUT); 981 | pinMode(AD5, INPUT); 982 | pinMode(AD6, INPUT); 983 | pinMode(AD7, INPUT); 984 | pinMode(AD8, INPUT); 985 | pinMode(AD9, INPUT); 986 | pinMode(AD10, INPUT); 987 | pinMode(AD11, INPUT); 988 | pinMode(AD12, INPUT); 989 | pinMode(AD13, INPUT); 990 | pinMode(AD14, INPUT); 991 | 992 | pinMode(WR, INPUT); 993 | pinMode(RD, INPUT); 994 | pinMode(MREQ, INPUT); 995 | pinMode(RFSH, INPUT); 996 | pinMode(IOREQ, INPUT); 997 | pinMode(M1, INPUT); 998 | 999 | // Databus can be input or output, start as an output 1000 | pinMode(D0, OUTPUT); 1001 | pinMode(D1, OUTPUT); 1002 | pinMode(D2, OUTPUT); 1003 | pinMode(D3, OUTPUT); 1004 | pinMode(D4, OUTPUT); 1005 | pinMode(D5, OUTPUT); 1006 | pinMode(D6, OUTPUT); 1007 | pinMode(D7, OUTPUT); 1008 | 1009 | pinMode(RESET, OUTPUT); 1010 | pinMode(Z_CLK, OUTPUT); 1011 | pinMode(INT, OUTPUT); 1012 | 1013 | digitalWrite(INT, HIGH); 1014 | 1015 | // initial values 1016 | digitalWrite(RESET, LOW); 1017 | digitalWrite(Z_CLK, HIGH); 1018 | 1019 | // tft.setCursor (1, 1); 1020 | // tft.print("Z80 TEST"); 1021 | 1022 | performZ80Reset(); 1023 | 1024 | // tft.fillRect (0, CONSOLE_START_Y-8, 240, 2, ILI9341_BLUE); 1025 | } 1026 | 1027 | elapsedMillis timer_seconds; 1028 | byte timer_seconds_intvector = 2; 1029 | 1030 | elapsedMillis timer_timeSlice; 1031 | byte timer_timeSlice_intvector = 6; 1032 | short timer_timeSlice_time = 150; 1033 | 1034 | void loop() { 1035 | 1036 | if (hardHalt) 1037 | { 1038 | return; 1039 | } 1040 | 1041 | cycle++; 1042 | 1043 | if (ioSerialInitialized && ioSerialIntVector) 1044 | { 1045 | 1046 | if (!ioSerialINTDebounce && (Serial.available() > 0)) { 1047 | digitalWrite(INT, LOW); 1048 | 1049 | currentInterruptVector = ioSerialIntVector; 1050 | currentInterrupt = 1; 1051 | ioSerialINTDebounce = 1; 1052 | } 1053 | else if (Serial.available() ==0) 1054 | { 1055 | ioSerialINTDebounce = 0; 1056 | } 1057 | } 1058 | 1059 | if ((timer_timeSlice > timer_timeSlice_time) && !currentInterrupt) 1060 | { 1061 | timer_timeSlice = 0; 1062 | digitalWrite(INT, LOW); 1063 | currentInterruptVector = timer_timeSlice_intvector; 1064 | currentInterrupt = 1; 1065 | } 1066 | /* 1067 | if ((timer_seconds > 1000) && !currentInterrupt) 1068 | { 1069 | timer_seconds = 0; 1070 | digitalWrite(INT, LOW); 1071 | currentInterruptVector = timer_seconds_intvector; 1072 | currentInterrupt = 1; 1073 | }*/ 1074 | 1075 | digitalWrite(Z_CLK, HIGH); 1076 | 1077 | updateZ80Control(); 1078 | 1079 | if (RFSH_val==1) { 1080 | // skip cycles that are just refshing dram 1081 | digitalWrite(Z_CLK, LOW); 1082 | return; 1083 | } 1084 | 1085 | //Use this for debugging if need be 1086 | //delay(DELAY); 1087 | 1088 | if (currentInterrupt>0) { 1089 | 1090 | if (IOREQ_val && M1_val) // interrupt ack 1091 | { 1092 | digitalWrite(INT, HIGH); 1093 | currentInterrupt = 0; 1094 | dataBus = currentInterruptVector; 1095 | writeDataBus(); 1096 | } 1097 | } 1098 | 1099 | readAddressBus(); 1100 | 1101 | if (MEMREQ_val) { 1102 | if (RD_val) { 1103 | if (addressBus < Z80_RAM_LENGTH) { 1104 | dataBus = Z80_RAM[addressBus]; 1105 | } else { 1106 | dataBus = 0x0; 1107 | } 1108 | writeDataBus(); 1109 | } else if (WR_val) { 1110 | readDataBus(); 1111 | if (addressBus < Z80_RAM_LENGTH) { 1112 | Z80_RAM[addressBus] = dataBus; 1113 | } 1114 | } 1115 | } 1116 | 1117 | 1118 | 1119 | if (IOREQ_val && (ioDebounce == 0) && !M1_val) 1120 | { 1121 | ioDebounce = 1; 1122 | unsigned short portAddress = addressBus & 0x00FF; 1123 | if (RD_val) { 1124 | if (portAddress == PORT_SERIAL_CMD) 1125 | { 1126 | dataBus = Serial.available(); 1127 | } 1128 | else if (portAddress == PORT_SERIAL_DATA) 1129 | { 1130 | dataBus = Serial.read(); 1131 | } 1132 | else if (portAddress == PORT_DISP_SETROW) 1133 | { 1134 | dataBus = console_current_row; 1135 | } 1136 | else if (portAddress == PORT_DISP_SETCOL) 1137 | { 1138 | dataBus = console_current_col; 1139 | } 1140 | else if (ioVramBankSet && ( addressBus == PORT_RAM_BANK_RESET)) 1141 | { 1142 | // PORT_RAM_BANK_RESET is a special case 16-bit port 1143 | ioVramBankSet = 0; 1144 | } 1145 | else if (portAddress == PORT_VRAM_SIZE) 1146 | { 1147 | dataBus = (uint8_t)(((uint16_t)Z80_VRAM_LENGTH) >> 8U); 1148 | } 1149 | else if (portAddress == PORT_RAM_SIZE) 1150 | { 1151 | dataBus = (uint8_t)(((uint16_t)Z80_RAM_LENGTH) >> 8U); 1152 | } 1153 | else if (portAddress == PORT_VRAM_PALETTE_IDX) 1154 | { 1155 | dataBus = ioVramPaletteIdx; 1156 | } 1157 | writeDataBus(); 1158 | 1159 | } else if (WR_val) { 1160 | readDataBus(); 1161 | 1162 | if (ioVramBankSet) 1163 | { 1164 | #if 0 1165 | Serial.println(fmtstring("VRAM WR : 0x%04X = 0x%02X", addressBus, dataBus)); 1166 | #endif 1167 | Z80_VRAM[addressBus] = dataBus; 1168 | } 1169 | else if (portAddress == PORT_DISP_CLEAR) 1170 | { 1171 | tft.fillScreen(ILI9341_BLACK); 1172 | } 1173 | else if (portAddress == PORT_VRAM_BUFFER_LOC) 1174 | { 1175 | ioVramBuffer = ((unsigned short)dataBus) << 8U; 1176 | } 1177 | else if (portAddress == PORT_RAM_BANK_SET) 1178 | { 1179 | ioVramBankSet = 1; 1180 | } 1181 | else if (portAddress == PORT_VRAM_DRAW) 1182 | { 1183 | vramDraw(); 1184 | } 1185 | else if (portAddress == PORT_VRAM_PALETTE_IDX) 1186 | { 1187 | ioVramPaletteIdx = dataBus; 1188 | } 1189 | else if (portAddress == PORT_VRAM_SETMODE) 1190 | { 1191 | ioVramDisplayMode = dataBus; 1192 | } 1193 | else if (portAddress == PORT_SERIAL_CMD) 1194 | { 1195 | if (ioSerialCurrentMode == SERIAL_CMD_READY) 1196 | { 1197 | //ready for commands, so put us in the right mode 1198 | if (dataBus == SERIAL_CMD_INIT) 1199 | { 1200 | //Serial.begin(ioSerialRate); 1201 | // Disabled waiting for serial as Teensy can be very troublesome with it. 1202 | while (!Serial); 1203 | ioSerialInitialized = 1; 1204 | } 1205 | else 1206 | { 1207 | ioSerialCurrentMode = dataBus; 1208 | } 1209 | } else { 1210 | //take data for the given mode 1211 | if (ioSerialCurrentMode == SERIAL_CMD_SET_INTVECTOR) 1212 | { 1213 | ioSerialIntVector = dataBus; 1214 | ioSerialCurrentMode = SERIAL_CMD_READY; 1215 | } 1216 | else if (ioSerialCurrentMode == SERIAL_CMD_SET_RATE) 1217 | { 1218 | ioSerialCurrentMode = SERIAL_CMD_SET_RATE_2; 1219 | ioSerialRate = dataBus; 1220 | } 1221 | else if (ioSerialCurrentMode == SERIAL_CMD_SET_RATE_2) 1222 | { 1223 | ioSerialCurrentMode = SERIAL_CMD_READY; 1224 | ioSerialRate |= (((unsigned short)dataBus)<<8U); 1225 | } 1226 | } 1227 | } 1228 | else if (portAddress == PORT_SERIAL_DATA) 1229 | { 1230 | Serial.write(dataBus); 1231 | } 1232 | else if (portAddress == PORT_DISP_PUTCHAR) 1233 | { 1234 | char c = dataBus; 1235 | //maybe add this to all debug routines and then only call it on a setcolour i/o 1236 | tft.setTextColor( console_current_color, ILI9341_BLACK); 1237 | tft.setCursor (CONSOLE_START_X + (console_current_col*CONSOLE_FONTX), CONSOLE_START_Y + (console_current_row*CONSOLE_FONTY)); 1238 | tft.print(fmtstring("%c", c)); 1239 | 1240 | console_current_col++; 1241 | if (console_current_col >= CONSOLE_COLUMNS) { 1242 | console_current_col = 0; 1243 | console_current_row++; 1244 | } 1245 | if (console_current_row >= CONSOLE_ROWS) { 1246 | console_current_row = 0; 1247 | } 1248 | } 1249 | else if (portAddress == PORT_DISP_SETROW) 1250 | { 1251 | console_current_row = dataBus; 1252 | if (console_current_row >= CONSOLE_ROWS) { 1253 | console_current_row = 0; 1254 | } 1255 | } 1256 | else if (portAddress == PORT_DISP_SETCOL) 1257 | { 1258 | console_current_col = dataBus; 1259 | 1260 | if (console_current_col >= CONSOLE_COLUMNS) { 1261 | console_current_col = 0; 1262 | } 1263 | } 1264 | else if (portAddress == PORT_DISP_SETCOLOUR) 1265 | { 1266 | if ((console_current_color_state&0x1)==0x1) 1267 | { 1268 | console_current_color |= dataBus<<8U; 1269 | } 1270 | else 1271 | { 1272 | console_current_color = dataBus; 1273 | } 1274 | console_current_color_state++; 1275 | } 1276 | else if (portAddress == PORT_FILESYS_READ_WRITE) 1277 | { 1278 | /* 1279 | * Filesystem READ command. 1280 | * Read an operation command from the cmd ptr. 1281 | * Execute the command given 1282 | */ 1283 | if (ioFileSysRWCurrentMode == FILESYS_RW_READY) 1284 | { 1285 | //ready for commands, so put us in the right mode 1286 | if (dataBus == FILESYS_RW_EXEC) 1287 | { 1288 | if (ioFileSysRWCmdMemPtr) 1289 | { 1290 | if (ioFileSysCurrentFile.isOpen()) 1291 | { 1292 | #define CMD_READ 0 1293 | #define CMD_WRITE 1 1294 | struct { 1295 | uint8_t error_code; 1296 | uint8_t op_type; 1297 | uint16_t block_offset; 1298 | uint16_t block_size; 1299 | uint16_t mem_buffer_ptr; 1300 | } __attribute__((packed)) command; 1301 | 1302 | memcpy(&command, &Z80_RAM[ioFileSysRWCmdMemPtr], sizeof(command)); 1303 | 1304 | #if 0 1305 | tft.setCursor (20, 20); 1306 | tft.println(fmtstring("CMD: %d,%d,%d,0x%04x.", 1307 | command.op_type, command.block_offset, command.block_size, 1308 | command.mem_buffer_ptr)); 1309 | #endif 1310 | 1311 | if (command.op_type == CMD_READ) 1312 | { 1313 | if (ioFileSysCurrentFile.seekSet(command.block_offset)) 1314 | { 1315 | short readbytes = ioFileSysCurrentFile.read( 1316 | &Z80_RAM[command.mem_buffer_ptr], 1317 | command.block_size); 1318 | if (readbytes != command.block_size) 1319 | { 1320 | Z80_RAM[ioFileSysRWCmdMemPtr] = 1; 1321 | } 1322 | else 1323 | { 1324 | Z80_RAM[ioFileSysRWCmdMemPtr] = 0; 1325 | } 1326 | } 1327 | else 1328 | { 1329 | Z80_RAM[ioFileSysRWCmdMemPtr] = 1; 1330 | } 1331 | } 1332 | else if (command.op_type == CMD_WRITE) 1333 | { 1334 | if (ioFileSysCurrentFile.seekSet(command.block_offset)) 1335 | { 1336 | short writebytes = ioFileSysCurrentFile.write( 1337 | &Z80_RAM[command.mem_buffer_ptr], 1338 | command.block_size); 1339 | if (writebytes != command.block_size) 1340 | { 1341 | Z80_RAM[ioFileSysRWCmdMemPtr] = 3; 1342 | } 1343 | else 1344 | { 1345 | Z80_RAM[ioFileSysRWCmdMemPtr] = 0; 1346 | } 1347 | } 1348 | else 1349 | { 1350 | Z80_RAM[ioFileSysRWCmdMemPtr] = 2; 1351 | } 1352 | } 1353 | } 1354 | else 1355 | { 1356 | //first byte is the error condition 1357 | Z80_RAM[ioFileSysRWCmdMemPtr] = 1; 1358 | } 1359 | } 1360 | } 1361 | else if (dataBus == FILESYS_RW_SETCMDMEMPTR) 1362 | { 1363 | ioFileSysRWCurrentMode = dataBus; 1364 | } 1365 | } 1366 | else 1367 | { 1368 | //take data for the given mode 1369 | if (ioFileSysRWCurrentMode == FILESYS_RW_SETCMDMEMPTR) 1370 | { 1371 | ioFileSysRWCmdMemPtr = dataBus; 1372 | ioFileSysRWCurrentMode = FILESYS_RW_SETCMDMEMPTR_2; 1373 | } 1374 | else if (ioFileSysRWCurrentMode == FILESYS_RW_SETCMDMEMPTR_2) 1375 | { 1376 | ioFileSysRWCmdMemPtr |= dataBus<<8U; 1377 | ioFileSysRWCurrentMode = FILESYS_RW_READY; 1378 | } 1379 | } 1380 | } 1381 | else if (portAddress == PORT_FILESYS_OPEN) 1382 | { 1383 | /* 1384 | * Filesystem OPEN command. 1385 | * Open a file with filename in given memory location 1386 | * Mem pointer should be a success byte followed by the 1387 | * access required then the file to open as null-terminated ascii. 1388 | */ 1389 | if (ioFileSysOpenCurrentMode == FILESYS_OPEN_READY) 1390 | { 1391 | //ready for commands, so put us in the right mode 1392 | if (dataBus == FILESYS_CLOSE_FILE) 1393 | { 1394 | // Just closes the currently open file. 1395 | if (ioFileSysCurrentFile.isOpen()) 1396 | { 1397 | ioFileSysCurrentFile.close(); 1398 | } 1399 | } 1400 | else if (dataBus == FILESYS_OPEN_OPENFILE) 1401 | { 1402 | if (ioFileSysOpenMemPtr) 1403 | { 1404 | if (!ioFileSysCurrentFile.isOpen()) 1405 | { 1406 | const char* filename = (const char*)&Z80_RAM[ioFileSysOpenMemPtr+7]; 1407 | #if 0 1408 | Serial.println(fmtstring("opening... '%s'", filename)); 1409 | #endif 1410 | // special case: root dir 1411 | if (filename[0]=='/' && filename[1]==0) 1412 | { 1413 | ioFileSysCWD.openRoot(volume); 1414 | ioFileSysCurrentFile.openRoot(volume); 1415 | Z80_RAM[ioFileSysOpenMemPtr] = 0; 1416 | Z80_RAM[ioFileSysOpenMemPtr+1] = 0; 1417 | Z80_RAM[ioFileSysOpenMemPtr+2] = 0; 1418 | Z80_RAM[ioFileSysOpenMemPtr+3] = 0; 1419 | Z80_RAM[ioFileSysOpenMemPtr+4] = 0; 1420 | Z80_RAM[ioFileSysOpenMemPtr+5] = 1; // dir flag 1421 | } 1422 | else 1423 | { 1424 | byte open_type = Z80_RAM[ioFileSysOpenMemPtr+6]; 1425 | 1426 | uint8_t flag = 0; 1427 | switch (open_type) 1428 | { 1429 | case OPEN_READ: 1430 | flag = O_READ; 1431 | break; 1432 | case OPEN_WRITE: 1433 | flag = O_WRITE| O_SYNC; 1434 | break; 1435 | case OPEN_WRITE_CREATE: 1436 | flag = O_WRITE | O_CREAT | O_SYNC; 1437 | break; 1438 | case OPEN_APPEND: 1439 | flag = O_APPEND | O_SYNC; 1440 | break; 1441 | case OPEN_RDWR: 1442 | flag = O_RDWR | O_SYNC; 1443 | break; 1444 | default: 1445 | break; 1446 | } 1447 | 1448 | ioFileSysCurrentFile.open( 1449 | ioFileSysCWD, 1450 | filename, 1451 | flag); 1452 | 1453 | if (ioFileSysCurrentFile.isOpen()) 1454 | { 1455 | Z80_RAM[ioFileSysOpenMemPtr] = 0; 1456 | uint32_t size = ioFileSysCurrentFile.fileSize(); 1457 | memcpy(&Z80_RAM[ioFileSysOpenMemPtr+1], &size, 4); 1458 | Z80_RAM[ioFileSysOpenMemPtr+5] = ioFileSysCurrentFile.isDir()?1:0; 1459 | 1460 | } 1461 | else 1462 | { 1463 | Z80_RAM[ioFileSysOpenMemPtr] = 2; 1464 | } 1465 | } 1466 | } 1467 | else 1468 | { 1469 | Z80_RAM[ioFileSysOpenMemPtr] = 1; 1470 | } 1471 | } 1472 | } 1473 | else if (dataBus == FILESYS_OPEN_SETMEMPTR) 1474 | { 1475 | ioFileSysOpenCurrentMode = dataBus; 1476 | } 1477 | } 1478 | else 1479 | { 1480 | //take data for the given mode 1481 | if (ioFileSysOpenCurrentMode == FILESYS_OPEN_SETMEMPTR) 1482 | { 1483 | ioFileSysOpenMemPtr = dataBus; 1484 | ioFileSysOpenCurrentMode = FILESYS_OPEN_SETMEMPTR_2; 1485 | } 1486 | else if (ioFileSysOpenCurrentMode == FILESYS_OPEN_SETMEMPTR_2) 1487 | { 1488 | ioFileSysOpenMemPtr |= dataBus<<8U; 1489 | ioFileSysOpenCurrentMode = FILESYS_OPEN_READY; 1490 | } 1491 | } 1492 | } 1493 | else if (portAddress == PORT_FILESYS_NEXT) 1494 | { 1495 | /* 1496 | * Filesystem NEXT command. 1497 | * If the current open file is a directory, providing the 1498 | * port with an area of memory using the SETMEMPTR command 1499 | * will allow signalling the GETNEXT command, which will write 1500 | * the next file in the directory sequence to the area of memory. 1501 | */ 1502 | if (ioFileSysNextCurrentMode == FILESYS_NEXT_READY) 1503 | { 1504 | //ready for commands, so put us in the right mode 1505 | if (dataBus == FILESYS_NEXT_GETNEXT) 1506 | { 1507 | if (ioFileSysNextMemPtr) 1508 | { 1509 | if (ioFileSysCurrentFile.isDir()) 1510 | { 1511 | // Modified from SD.cpp 1512 | dir_t p; 1513 | 1514 | Z80_RAM[ioFileSysNextMemPtr] = 5; 1515 | 1516 | while (ioFileSysCurrentFile.readDir(&p) > 0) 1517 | { 1518 | if (p.name[0] == DIR_NAME_FREE) { 1519 | //no more files 1520 | Z80_RAM[ioFileSysNextMemPtr] = 1; 1521 | break; 1522 | } 1523 | 1524 | if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.') { 1525 | continue; 1526 | } 1527 | 1528 | // only list subdirectories and files 1529 | if (!DIR_IS_FILE_OR_SUBDIR(&p)) { 1530 | continue; 1531 | } 1532 | 1533 | char name[13]; 1534 | ioFileSysCurrentFile.dirName(p, name); 1535 | SdFile f; 1536 | tft.setCursor (20, 20); 1537 | if (f.open(ioFileSysCurrentFile, name, O_RDONLY)) { 1538 | // ok 1539 | 1540 | uint32_t size = (f.isDir()?0U:f.fileSize()); 1541 | name[12] = 0; 1542 | 1543 | 1544 | Z80_RAM[ioFileSysNextMemPtr] = 0; 1545 | memcpy(&Z80_RAM[ioFileSysNextMemPtr + 1], &size, 4); 1546 | 1547 | Z80_RAM[ioFileSysNextMemPtr + 5] = (f.isDir())?1:0; 1548 | memcpy(&Z80_RAM[ioFileSysNextMemPtr + 6], &name[0], 13); 1549 | f.close(); 1550 | break; 1551 | } else { 1552 | // Read error 1553 | Z80_RAM[ioFileSysNextMemPtr] = 2; 1554 | break; 1555 | } 1556 | } 1557 | } 1558 | else 1559 | { 1560 | Z80_RAM[ioFileSysNextMemPtr] = 2; 1561 | } 1562 | } 1563 | } 1564 | else if (dataBus == FILESYS_NEXT_SETMEMPTR) 1565 | { 1566 | ioFileSysNextCurrentMode = dataBus; 1567 | } 1568 | } 1569 | else 1570 | { 1571 | //take data for the given mode 1572 | if (ioFileSysNextCurrentMode == FILESYS_NEXT_SETMEMPTR) 1573 | { 1574 | ioFileSysNextMemPtr = dataBus; 1575 | ioFileSysNextCurrentMode = FILESYS_NEXT_SETMEMPTR_2; 1576 | } 1577 | else if (ioFileSysNextCurrentMode == FILESYS_NEXT_SETMEMPTR_2) 1578 | { 1579 | ioFileSysNextMemPtr |= dataBus<<8U; 1580 | ioFileSysNextCurrentMode = FILESYS_NEXT_READY; 1581 | } 1582 | } 1583 | } 1584 | } 1585 | } 1586 | else 1587 | { 1588 | // to deal with cycle timings figure 7, timing, z80 manual 1589 | if (ioDebounce > 0) 1590 | { 1591 | ioDebounce++; 1592 | if (ioDebounce >= 3) 1593 | { 1594 | ioDebounce = 0; 1595 | } 1596 | } 1597 | } 1598 | 1599 | 1600 | #if DBG_DRAW_CYCLE 1601 | debugDrawCycle(); 1602 | #endif 1603 | 1604 | #if DBG_DRAW_ADDR 1605 | debugDrawAddressBus(); 1606 | #endif 1607 | 1608 | #if DBG_DRAW_DATA 1609 | debugDrawDataBus(); 1610 | #endif 1611 | 1612 | #if MEMORY_DISPLAY 1613 | memoryDisplayUpdate(); 1614 | #endif 1615 | 1616 | #if VRAM_DISPLAY 1617 | vramDisplayUpdate(); 1618 | #endif 1619 | 1620 | digitalWrite(Z_CLK, LOW); 1621 | 1622 | #if DBG_DRAW_LOG 1623 | debugDrawLog(); 1624 | #endif 1625 | } 1626 | 1627 | void readAddressBus() { 1628 | addressBus = 0; 1629 | addressBus |= ((digitalRead(AD0)==HIGH)?1:0)<<0; 1630 | addressBus |= ((digitalRead(AD1)==HIGH)?1:0)<<1; 1631 | addressBus |= ((digitalRead(AD2)==HIGH)?1:0)<<2; 1632 | addressBus |= ((digitalRead(AD3)==HIGH)?1:0)<<3; 1633 | addressBus |= ((digitalRead(AD4)==HIGH)?1:0)<<4; 1634 | addressBus |= ((digitalRead(AD5)==HIGH)?1:0)<<5; 1635 | addressBus |= ((digitalRead(AD6)==HIGH)?1:0)<<6; 1636 | addressBus |= ((digitalRead(AD7)==HIGH)?1:0)<<7; 1637 | addressBus |= ((digitalRead(AD8)==HIGH)?1:0)<<8; 1638 | addressBus |= ((digitalRead(AD9)==HIGH)?1:0)<<9; 1639 | addressBus |= ((digitalRead(AD10)==HIGH)?1:0)<<10; 1640 | addressBus |= ((analogRead(AD11)>512)?1:0)<<11; 1641 | addressBus |= ((analogRead(AD12)>512)?1:0)<<12; 1642 | addressBus |= ((analogRead(AD13)>512)?1:0)<<13; 1643 | addressBus |= ((analogRead(AD14)>512)?1:0)<<14; 1644 | } 1645 | 1646 | void readDataBus() { 1647 | pinMode(D0, INPUT); 1648 | pinMode(D1, INPUT); 1649 | pinMode(D2, INPUT); 1650 | pinMode(D3, INPUT); 1651 | pinMode(D4, INPUT); 1652 | pinMode(D5, INPUT); 1653 | pinMode(D6, INPUT); 1654 | pinMode(D7, INPUT); 1655 | 1656 | dataBus = 0; 1657 | dataBus |= ((digitalRead(D0)==HIGH)?1:0)<<0; 1658 | dataBus |= ((digitalRead(D1)==HIGH)?1:0)<<1; 1659 | dataBus |= ((digitalRead(D2)==HIGH)?1:0)<<2; 1660 | dataBus |= ((digitalRead(D3)==HIGH)?1:0)<<3; 1661 | dataBus |= ((digitalRead(D4)==HIGH)?1:0)<<4; 1662 | dataBus |= ((digitalRead(D5)==HIGH)?1:0)<<5; 1663 | dataBus |= ((digitalRead(D6)==HIGH)?1:0)<<6; 1664 | dataBus |= ((digitalRead(D7)==HIGH)?1:0)<<7; 1665 | } 1666 | 1667 | void writeDataBus() { 1668 | pinMode(D0, OUTPUT); 1669 | pinMode(D1, OUTPUT); 1670 | pinMode(D2, OUTPUT); 1671 | pinMode(D3, OUTPUT); 1672 | pinMode(D4, OUTPUT); 1673 | pinMode(D5, OUTPUT); 1674 | pinMode(D6, OUTPUT); 1675 | pinMode(D7, OUTPUT); 1676 | 1677 | digitalWrite(D0, (dataBus&(1<<0))?HIGH:LOW); 1678 | digitalWrite(D1, (dataBus&(1<<1))?HIGH:LOW); 1679 | digitalWrite(D2, (dataBus&(1<<2))?HIGH:LOW); 1680 | digitalWrite(D3, (dataBus&(1<<3))?HIGH:LOW); 1681 | digitalWrite(D4, (dataBus&(1<<4))?HIGH:LOW); 1682 | digitalWrite(D5, (dataBus&(1<<5))?HIGH:LOW); 1683 | digitalWrite(D6, (dataBus&(1<<6))?HIGH:LOW); 1684 | digitalWrite(D7, (dataBus&(1<<7))?HIGH:LOW); 1685 | } 1686 | 1687 | void debugDrawCycle() { 1688 | tft.setTextColor( ILI9341_WHITE, ILI9341_BLACK); 1689 | tft.setCursor (76, 1); 1690 | tft.print(cycle); 1691 | } 1692 | 1693 | void debugDrawStatusLines() { 1694 | tft.setTextColor( ILI9341_WHITE, ILI9341_BLACK); 1695 | tft.setCursor (76, 160); 1696 | tft.print(fmtstring("[%c %c %c %c] ", (M1_val?'F':' '), (RFSH_val?'H':' '), (MEMREQ_val?'M':' '), (IOREQ_val?'I':' '))); 1697 | } 1698 | 1699 | void debugDrawLog() { 1700 | 1701 | if (GFX_LOG_LINES > 0) 1702 | { 1703 | delay(DBG_DRAW_LOG_DELAY); 1704 | tft.setRotation(0); // 0 - Portrait, 1 - Lanscape 1705 | tft.setTextColor( ILI9341_WHITE, ILI9341_BLACK); 1706 | if (current_line >= GFX_LOG_LINES) 1707 | { 1708 | current_line = 0; 1709 | } 1710 | char* str = fmtstring("%02x: ? [%c %c %c %c] ", cycle, (M1_val?'F':' '), (RFSH_val?'H':' '), (MEMREQ_val?'M':' '), (IOREQ_val?'I':' ')); 1711 | 1712 | int log_offset = GFX_LOG_START + (current_line*10); 1713 | if (IOREQ_val && M1_val) { 1714 | str = fmtstring("%02x: INT ACK DB:0x%02x", cycle, dataBus); 1715 | } else if (M1_val && !MEMREQ_val && !RD_val) { 1716 | str = fmtstring("%02x: I Fetch", cycle); 1717 | } else if (M1_val && MEMREQ_val && RD_val) { 1718 | str = fmtstring("%02x: I Read 0x%04x", cycle, addressBus); 1719 | } else if (MEMREQ_val && RD_val) { 1720 | str = fmtstring("%02x: Mem Rd 0x%04x=0x%02x", cycle, addressBus, dataBus); 1721 | } else if (MEMREQ_val && WR_val) { 1722 | str = fmtstring("%02x: Mem Wr 0x%04x=0x%02x", cycle, addressBus, dataBus); 1723 | } else if (IOREQ_val && RD_val) { 1724 | str = fmtstring("%02x: IO Rd 0x%04x=0x%02x", cycle, addressBus, dataBus); 1725 | } else if (IOREQ_val && WR_val) { 1726 | str = fmtstring("%02x: IO Wr 0x%04x=0x%02x", cycle, addressBus, dataBus); 1727 | } else if (RFSH_val && RD_val) { 1728 | str = fmtstring("%02x: RFSH 0x%04x", cycle, addressBus); 1729 | } else if (RFSH_val && !M1_val) { 1730 | str = fmtstring("%02x: RFSH 0x%04x", cycle, addressBus); 1731 | } 1732 | tft.fillRect (0, log_offset, 196, 10, ILI9341_BLACK); 1733 | tft.setCursor (2, log_offset ); 1734 | tft.print(str); 1735 | 1736 | tft.fillRect (0, GFX_LOG_START, 1, GFX_LOG_LINES*10, ILI9341_BLACK); 1737 | 1738 | tft.fillRect (0, log_offset, 1, 10, ILI9341_YELLOW); 1739 | 1740 | current_line++; 1741 | 1742 | tft.setRotation(1); // 0 - Portrait, 1 - Lanscape 1743 | } 1744 | 1745 | skip: 1746 | return; 1747 | } 1748 | 1749 | void memoryDisplayUpdate() { 1750 | tft.setCursor (0, GFX_CONTROL_START-8); 1751 | 1752 | tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK); 1753 | for (int x = 0; x < Z80_RAM_LENGTH; x++) 1754 | { 1755 | if ((x%10)==0) 1756 | { 1757 | tft.println(" "); 1758 | tft.print(fmtstring("0x%04X: ", x)); 1759 | } 1760 | 1761 | byte data = Z80_RAM[x]; 1762 | tft.print(fmtstring("%02X ", data)); 1763 | 1764 | } 1765 | } 1766 | 1767 | void vramDisplayUpdate() { 1768 | short vscr_addr = ioVramBuffer; 1769 | /* 1770 | tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK); 1771 | 1772 | for (int y=0; y < CONSOLE_ROWS; y++) 1773 | { 1774 | for (int x = 0; x < CONSOLE_COLUMNS; x++) 1775 | { 1776 | short vscr_cur = (y*CONSOLE_COLUMNS) + x; 1777 | unsigned char current = Z80_RAM[vscr_addr + vscr_cur]; 1778 | if (current != last_disp[vscr_cur]) 1779 | { 1780 | last_disp[vscr_cur] = current; 1781 | 1782 | tft.setCursor (CONSOLE_START_X + (x*CONSOLE_FONTX), CONSOLE_START_Y + (y*CONSOLE_FONTY)); 1783 | tft.print(fmtstring("%c", current)); 1784 | } 1785 | } 1786 | } */ 1787 | } 1788 | 1789 | void debugDrawAddressBus() { 1790 | 1791 | tft.setTextColor( ILI9341_WHITE, ILI9341_BLACK); 1792 | tft.setCursor (1, GFX_ADDR_START); 1793 | tft.print("ADDR: 0x"); 1794 | tft.println(addressBus, HEX); 1795 | tft.print(" B"); 1796 | tft.print('X'); 1797 | tft.print('X'); 1798 | tft.print((addressBus&(1<<13))?'1':'0'); 1799 | tft.print((addressBus&(1<<12))?'1':'0'); 1800 | tft.print((addressBus&(1<<11))?'1':'0'); 1801 | tft.print((addressBus&(1<<10))?'1':'0'); 1802 | tft.print((addressBus&(1<<9))?'1':'0'); 1803 | tft.print((addressBus&(1<<8))?'1':'0'); 1804 | tft.print((addressBus&(1<<7))?'1':'0'); 1805 | tft.print((addressBus&(1<<6))?'1':'0'); 1806 | tft.print((addressBus&(1<<5))?'1':'0'); 1807 | tft.print((addressBus&(1<<4))?'1':'0'); 1808 | tft.print((addressBus&(1<<3))?'1':'0'); 1809 | tft.print((addressBus&(1<<2))?'1':'0'); 1810 | tft.print((addressBus&(1<<1))?'1':'0'); 1811 | tft.print((addressBus&(1<<0))?'1':'0'); 1812 | } 1813 | 1814 | void debugDrawDataBus() { 1815 | tft.setTextColor( ILI9341_WHITE, ILI9341_BLACK); 1816 | tft.setCursor (1, GFX_DATA_START); 1817 | tft.print("DATA: 0x"); 1818 | tft.println(dataBus, HEX); 1819 | tft.print(" B"); 1820 | tft.print((dataBus&(1<<7))?'1':'0'); 1821 | tft.print((dataBus&(1<<6))?'1':'0'); 1822 | tft.print((dataBus&(1<<5))?'1':'0'); 1823 | tft.print((dataBus&(1<<4))?'1':'0'); 1824 | tft.print((dataBus&(1<<3))?'1':'0'); 1825 | tft.print((dataBus&(1<<2))?'1':'0'); 1826 | tft.print((dataBus&(1<<1))?'1':'0'); 1827 | tft.print((dataBus&(1<<0))?'1':'0'); 1828 | } 1829 | --------------------------------------------------------------------------------