├── .gitignore ├── README.md ├── ans.txt ├── aoc-full.nes ├── aoc.asm ├── biosfnt.chr ├── biosfnt.map ├── build-fix.py ├── build.bat ├── build.sh ├── day1.asm ├── day10.asm ├── day10_input.asm ├── day11.asm ├── day11_input.asm ├── day12-a.png ├── day12-b.png ├── day12.asm ├── day12_input.asm ├── day13-a.png ├── day13-b.png ├── day13.asm ├── day13_input.asm ├── day14.asm ├── day14_input.asm ├── day1_input.asm ├── day2.asm ├── day2_input.asm ├── day3.asm ├── day3_input.asm ├── day4.asm ├── day4_input.asm ├── day5.asm ├── day5_input.asm ├── day6.asm ├── day6_input.asm ├── day7.asm ├── day7_input.asm ├── day8.asm ├── day8_input.asm ├── day9.asm ├── day9_input.asm ├── intro.png ├── macros.asm ├── math.asm ├── musicbank-8000.bin ├── nesasm-vs.exe ├── nesasmsrc ├── assemble.c ├── code.c ├── command.c ├── crc.c ├── defs.h ├── expr.c ├── expr.h ├── externs.h ├── func.c ├── input.c ├── inst.h ├── macro.c ├── main.c ├── map.c ├── mml.c ├── nes.c ├── nes.h ├── output.c ├── pce.c ├── pce.h ├── pcx.c ├── proc.c ├── protos.h ├── symbol.c ├── vars.h └── vs │ ├── nesasm-vs.sln │ ├── nesasm-vs.vcxproj │ └── nesasm-vs.vcxproj.filters ├── nss ├── intro-0.nam ├── intro-1.nam ├── intro-2.nam ├── intro-3.nam ├── intro.chr ├── intro.nam ├── intro.nss └── intro.pal ├── running.png ├── scripts └── intro-nt-fix.py ├── sym-fix.py ├── title.bmp └── title.xcf /.gitignore: -------------------------------------------------------------------------------- 1 | nesasm-fix 2 | aoc.nes 3 | aoc.fns 4 | *.deb 5 | fceux/ 6 | nesasm/ 7 | nesasmsrc/vs/.vs 8 | nesasmsrc/vs/nesasm-vs.vcxproj.user 9 | nesasmsrc/vs/x64 10 | musicbank.bin* 11 | hacks 12 | *.nsf 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Advent of Code 2021 - On an NES 2 | 3 | Quest to complete Advent of Code 2021 on a unmodified 8-bit NES. 4 | 5 | ![AoC 2021](intro.png) 6 | 7 | Should (and does) run on physical hardware. Uses MMC1 with 0x2000 (+0x800) bytes of RAM. Some of the challenges take **way** over an hour to compute the answer for. Does **not** work with PowerPAK (dont know why and at this point, I dont care). 8 | 9 | If you hate yourself and want to watch it for the serveral hours it takes to complete, just: 10 | 11 | 1) `(cd nesasmsrc && gcc *.c -o ../nesasm-fix)` to build the modified (required) nesasm version. 12 | 2) `./build.sh` 13 | 3) Run it and wait a brief eternity for it to finish. The awesome christmas tune was ripped from [here](https://www.bilibili.com/video/BV1nh411f77p/). Music does not loop so the vast majority of execution is spent in silent anguish. 14 | 15 | **EDIT:** I just added the ROM image... Just load it in your favorite emulator or write to cart. 16 | 17 | **Days completed:** 1,2,3,4,5,6,7,8,9,10,11,12,13,14. All of them! :D 18 | 19 | ### Day 12 20 | 21 | ![AoC 2021 - Day 12.a](day12-a.png) 22 | 23 | ![AoC 2021 - Day 12.b](day12-b.png) 24 | 25 | 26 | ### Day 13 27 | 28 | ![AoC 2021 - Day 13.a](day13-a.png) 29 | 30 | ![AoC 2021 - Day 13.b](day13-b.png) 31 | 32 | -------------------------------------------------------------------------------- /ans.txt: -------------------------------------------------------------------------------- 1 | # day 2 2 | 1580000, 1251263225 3 | 0x181be0, 0x4a94c2f9 4 | 5 | # day 3 6 | 3895776, 7928162 7 | 0x3b71e0, 0x78f962 -------------------------------------------------------------------------------- /aoc-full.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pellsson/aoc2021/e71a765ea4cd3293ac239f629dc87f45888fe470/aoc-full.nes -------------------------------------------------------------------------------- /biosfnt.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pellsson/aoc2021/e71a765ea4cd3293ac239f629dc87f45888fe470/biosfnt.chr -------------------------------------------------------------------------------- /biosfnt.map: -------------------------------------------------------------------------------- 1 | a^]YZUST_VW` !"#$%&'()*+,-./012345678[\X9:;<=>L?@ABCDEFGHIJKMNOPQR -------------------------------------------------------------------------------- /build-fix.py: -------------------------------------------------------------------------------- 1 | x = open('aoc.nes', 'rb').read() 2 | x += open('biosfnt.chr', 'rb').read() 3 | x += open('biosfnt.chr', 'rb').read() 4 | x += open('nss/intro.chr', 'rb').read() 5 | open('aoc-full.nes', 'wb').write(x) 6 | -------------------------------------------------------------------------------- /build.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | echo Building... 3 | nesasm-vs.exe aoc.asm 4 | echo Writing CHR... 5 | python -c "open('aoc-full.nes', 'wb').write(open('aoc.nes', 'rb').read()+open('biosfnt.chr', 'rb').read()+open('biosfnt.chr', 'rb').read()+open('nss/intro.chr', 'rb').read())" -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | echo Building... 2 | ./nesasm-fix -l 3 aoc.asm 3 | echo Writing CHR... 4 | python build-fix.py 5 | python sym-fix.py >> aoc.fns 6 | -------------------------------------------------------------------------------- /day1.asm: -------------------------------------------------------------------------------- 1 | INPUT .equ WORK 2 | SAVED_SEQUENCE .equ WORK+$4 3 | 4 | rewind_word: 5 | lda #2 6 | sta Param0 7 | rewind_by: 8 | sec 9 | lda INPUT 10 | sbc Param0 11 | sta INPUT 12 | lda INPUT+1 13 | sbc #$0 14 | sta INPUT+1 15 | rts 16 | 17 | do_pass_a: 18 | jsr read_next 19 | sta MathLhs 20 | jsr read_next 21 | sta MathLhs+1 22 | jsr read_next 23 | sta MathRhs 24 | jsr read_next 25 | sta MathRhs+1 26 | jsr rewind_word 27 | jsr math_sub16 28 | 29 | lda MathOut+1 30 | bpl .decreased 31 | inc Result 32 | bne .decreased 33 | inc Result+1 34 | .decreased: 35 | rts 36 | 37 | day1_solve_a: 38 | lda #LOW(day1_input) 39 | sta INPUT 40 | lda #HIGH(day1_input) 41 | sta INPUT+1 42 | .keep_solving: 43 | jsr do_pass_a 44 | lda #LOW(day1_input_end-2) 45 | cmp INPUT 46 | bne .keep_solving 47 | lda #HIGH(day1_input_end-2) 48 | cmp INPUT+1 49 | bne .keep_solving 50 | rts 51 | 52 | add_series: 53 | ; in[0]+in[1] 54 | jsr read_next 55 | sta MathLhs 56 | jsr read_next 57 | sta MathLhs+1 58 | jsr read_next 59 | sta MathRhs 60 | jsr read_next 61 | sta MathRhs+1 62 | jsr math_add16 63 | ; 64 | ; (in[0]+in[1])+in[2] 65 | ; 66 | lda MathOut 67 | sta MathLhs 68 | lda MathOut+1 69 | sta MathLhs+1 70 | jsr read_next 71 | sta MathRhs 72 | jsr read_next 73 | sta MathRhs+1 74 | jmp math_add16 75 | 76 | do_pass_b: 77 | jsr add_series 78 | ; 79 | ; Rewind by 4 to find the next series 80 | ; 81 | lda #4 82 | sta Param0 83 | jsr rewind_by 84 | lda MathOut 85 | sta SAVED_SEQUENCE 86 | lda MathOut+1 87 | sta SAVED_SEQUENCE+1 88 | jsr add_series 89 | ; 90 | ; Rewind to head of this series (to make it the new first series for next pass) 91 | ; 92 | lda #6 93 | sta Param0 94 | jsr rewind_by 95 | lda MathOut 96 | sta MathRhs 97 | lda MathOut+1 98 | sta MathRhs+1 99 | lda SAVED_SEQUENCE 100 | sta MathLhs 101 | lda SAVED_SEQUENCE+1 102 | sta MathLhs+1 103 | jsr math_sub16 104 | lda MathOut+1 105 | bpl .decreased 106 | inc Result 107 | bne .decreased 108 | inc Result+1 109 | .decreased: 110 | rts 111 | 112 | day1_solve_b: 113 | lda #LOW(day1_input) 114 | sta INPUT 115 | lda #HIGH(day1_input) 116 | sta INPUT+1 117 | .keep_solving: 118 | jsr do_pass_b 119 | lda #LOW(day1_input_end-6) 120 | cmp INPUT 121 | bne .keep_solving 122 | lda #HIGH(day1_input_end-6) 123 | cmp INPUT+1 124 | bne .keep_solving 125 | rts 126 | -------------------------------------------------------------------------------- /day10.asm: -------------------------------------------------------------------------------- 1 | INPUT .equ WORK 2 | D10_Num .equ WORK+$4 3 | D10_Corrupt .equ WORK+$5 ; and 6,7,8 4 | D10_SkipLine .equ WORK+$9 5 | D10_Target .equ WORK+$a 6 | D10_StackOff .equ WORK+$10 7 | D10_PtrScore .equ WORK+$12 ; and 3 8 | D10_I .equ WORK+$18 9 | D10_J .equ WORK+$19 10 | D10_NumBefore .equ WORK+$21 11 | D10_Tmp .equ WORK+$22 ; 23, 24, 25, 26 12 | D10_Stack .equ $6000 13 | D10_ScoreB .equ $6100 14 | D10_NumScore .equ $7000 ; 15 | 16 | d10_write_score: 17 | ldy #0 18 | sta [D10_PtrScore], Y 19 | inc D10_PtrScore 20 | bne .no_high 21 | inc D10_PtrScore+1 22 | .no_high: 23 | rts 24 | 25 | d10_pop: 26 | ldx D10_StackOff 27 | dex 28 | stx D10_StackOff 29 | lda D10_Stack,x 30 | rts 31 | 32 | d10_does_open: 33 | cmp #'(' 34 | beq .does 35 | cmp #'[' 36 | beq .does 37 | cmp #'{' 38 | beq .does 39 | cmp #'<' 40 | .does: 41 | rts 42 | 43 | d10_close: 44 | tay 45 | jsr d10_pop 46 | cpy #')' 47 | bne .not_para 48 | ldx #3 ; score 49 | ldy #0 50 | cmp #'(' 51 | bne .is_corrupt 52 | rts 53 | .not_para: 54 | cpy #']' 55 | bne .not_brack 56 | ldx #57 ; score 57 | ldy #0 58 | cmp #'[' 59 | bne .is_corrupt 60 | rts 61 | .not_brack: 62 | cpy #'}' 63 | bne .not_curl 64 | ldx #LOW(1197) ; score 65 | ldy #HIGH(1197) 66 | cmp #'{' 67 | bne .is_corrupt 68 | .return: 69 | rts 70 | .not_curl: 71 | cpy #'>' 72 | bne .is_corrupt 73 | ldx #LOW(25137) ; score 74 | ldy #HIGH(25137) 75 | cmp #'<' 76 | beq .return 77 | .is_corrupt: 78 | stx D10_Corrupt 79 | sty D10_Corrupt+1 80 | rts 81 | 82 | d10_read_line: 83 | lda #0 84 | sta D10_StackOff 85 | .next_byte: 86 | jsr read_next 87 | sta D10_Num 88 | cmp #0 89 | bne .not_eol 90 | lda #0 91 | sta D10_SkipLine 92 | rts 93 | .not_eol: 94 | ldx D10_SkipLine 95 | bne .next_byte 96 | jsr d10_does_open 97 | bne .does_not_open 98 | ; just write it to stack 99 | ldx D10_StackOff 100 | sta D10_Stack, x 101 | inx 102 | stx D10_StackOff 103 | bne .next_byte ; Always true 104 | .does_not_open: 105 | jsr d10_close 106 | lda D10_Corrupt 107 | beq .not_corrupt 108 | ; Corrupt 109 | inc D10_SkipLine 110 | .not_corrupt: 111 | jmp .next_byte 112 | 113 | d10_get_score_b: 114 | cmp #'(' 115 | bne .not_para 116 | lda #1 117 | rts 118 | .not_para: 119 | cmp #'[' 120 | bne .not_brack 121 | lda #2 122 | rts 123 | .not_brack: 124 | cmp #'{' 125 | bne .not_curl 126 | lda #3 127 | rts 128 | .not_curl: 129 | lda #4 130 | rts 131 | 132 | day10_solve_a: 133 | lda #0 134 | sta D10_NumScore 135 | lda #LOW(D10_ScoreB) 136 | sta D10_PtrScore 137 | lda #HIGH(D10_ScoreB) 138 | sta D10_PtrScore+1 139 | lda #LOW(day10_input) 140 | sta INPUT 141 | lda #HIGH(day10_input) 142 | sta INPUT+1 143 | .next: 144 | lda INPUT 145 | cmp #LOW(day10_input_end) 146 | bne .not_end 147 | lda INPUT+1 148 | cmp #HIGH(day10_input_end) 149 | bne .not_end 150 | rts 151 | .not_end: 152 | jsr d10_read_line 153 | lda D10_Corrupt 154 | beq .not_corrupt 155 | ; Solve for a 156 | macro_add32 Result, D10_Corrupt 157 | lda #0 158 | sta D10_Corrupt 159 | sta D10_Corrupt+1 160 | jmp .next 161 | .not_corrupt: 162 | lda #0 163 | sta MathLhs 164 | sta MathLhs+1 165 | sta MathLhs+2 166 | sta MathLhs+3 167 | .pop_more: 168 | jsr d10_hack_patch 169 | bne .skip_hack 170 | lda #5 171 | sta MathRhs 172 | jsr math_mul32 173 | jsr d10_pop 174 | jsr d10_get_score_b 175 | sta MathRhs 176 | macro_add32 MathOut, MathRhs 177 | tmm32 MathLhs, MathOut 178 | ldx D10_StackOff 179 | bne .pop_more 180 | .skip_hack: 181 | lda MathLhs 182 | jsr d10_write_score 183 | lda MathLhs+1 184 | jsr d10_write_score 185 | lda MathLhs+2 186 | jsr d10_write_score 187 | lda MathLhs+3 188 | jsr d10_write_score 189 | inc D10_NumScore 190 | jmp .next 191 | 192 | d10_hack_patch: 193 | ; Hack. We dont support 64-bit. 194 | ldx D10_StackOff 195 | cpx #1 196 | bne .dont_skip 197 | lda MathLhs+3 198 | and #$F0 199 | beq .dont_skip 200 | lda #$F0 201 | sta MathLhs+3 202 | rts 203 | .dont_skip: 204 | lda #0 205 | rts 206 | 207 | d10_score_at: 208 | sta MathLhs 209 | lda #0 210 | sta MathLhs+1 211 | asl MathLhs+1 212 | rol MathLhs ; *= 2 213 | asl MathLhs+1 214 | rol MathLhs 215 | lda #LOW(D10_ScoreB) 216 | sta MathRhs 217 | lda #HIGH(D10_ScoreB) 218 | sta MathRhs+1 219 | macro_add16 MathLhs, MathRhs 220 | lda MathLhs 221 | sta INPUT 222 | lda MathLhs+1 223 | sta INPUT+1 224 | jsr read_next 225 | sta MathLhs 226 | jsr read_next 227 | sta MathLhs+1 228 | jsr read_next 229 | sta MathLhs+2 230 | jsr read_next 231 | sta MathLhs+3 232 | rts 233 | 234 | d10_compare_ij: 235 | lda D10_J 236 | jsr d10_score_at 237 | tmm32 D10_Tmp, MathLhs 238 | lda D10_I 239 | jsr d10_score_at 240 | macro_is_less_u32 MathLhs, D10_Tmp, .is_less 241 | ; if (score[i] < score[j]) 242 | rts 243 | .is_less: 244 | inc D10_NumBefore 245 | rts 246 | 247 | d10_find_mid: 248 | ; Everything already at zero 249 | lda D10_NumScore 250 | lsr a 251 | sta D10_Target 252 | .gogo: 253 | lda #0 254 | sta D10_NumBefore 255 | sta D10_J 256 | lda D10_I 257 | cmp D10_NumScore 258 | bcs .done 259 | .next_inner: 260 | lda D10_J 261 | cmp D10_NumScore 262 | bcs .next_outer 263 | jsr d10_compare_ij 264 | inc D10_J 265 | jmp .next_inner 266 | .next_outer: 267 | lda D10_NumBefore 268 | cmp D10_Target 269 | beq .done 270 | inc D10_I 271 | jmp .gogo 272 | .done: 273 | ; This is the guy (or somehting broke completely)... 274 | rts 275 | 276 | day10_solve_b: 277 | jsr d10_find_mid 278 | lda D10_I 279 | jsr d10_score_at 280 | tmm32 Result, MathLhs 281 | rts 282 | -------------------------------------------------------------------------------- /day11.asm: -------------------------------------------------------------------------------- 1 | INPUT .equ WORK 2 | D11_X .equ WORK+$2 3 | D11_Y .equ WORK+$3 4 | D11_Tmp .equ WORK+$4 5 | D11_NX .equ WORK+$5 6 | D11_NY .equ WORK+$6 7 | D11_EX .equ WORK+$7 8 | D11_EY .equ WORK+$8 9 | D11_NumLit .equ WORK+$10 10 | D11_Step .equ WORK+$11 ; and 12 11 | D11_NumLitAll .equ WORK+$13 12 | D11_NumLitStep .equ WORK+$18 13 | D11_Board .equ $6000 14 | D11_ScoreB .equ $7000 15 | 16 | macro_walk_board .macro 17 | lda #0 18 | sta D11_X 19 | sta D11_Y 20 | .next\@: 21 | ldy D11_Y 22 | ldx D11_X 23 | jsr \1 24 | ldx D11_X 25 | inx 26 | stx D11_X 27 | cpx #12 28 | bmi .next\@ 29 | ldx #0 30 | stx D11_X 31 | ldy D11_Y 32 | iny 33 | sty D11_Y 34 | cpy #12 35 | bmi .next\@ 36 | .endm 37 | 38 | 39 | d11_init_board: 40 | cpx #0 41 | beq .border 42 | cpx #11 43 | beq .border 44 | cpy #0 45 | beq .border 46 | cpy #11 47 | beq .border 48 | jsr read_next 49 | ldx D11_X 50 | ldy D11_Y 51 | jmp d11_write_at 52 | .border: 53 | lda #$FF 54 | jmp d11_write_at 55 | 56 | d11_write_at: 57 | pha 58 | txa 59 | .top: 60 | dey 61 | bmi .done 62 | clc 63 | adc #12 64 | bne .top 65 | .done: 66 | tax 67 | pla 68 | sta D11_Board,x 69 | rts 70 | 71 | d11_read_at: 72 | txa 73 | .top: 74 | dey 75 | bmi .done 76 | clc 77 | adc #12 78 | bne .top 79 | .done: 80 | tax 81 | lda D11_Board,x 82 | rts 83 | 84 | d11_inc_squid: 85 | jsr d11_read_at 86 | sta D11_Tmp 87 | and #$80 88 | bne .dont 89 | lda D11_Tmp 90 | clc 91 | adc #1 92 | ldx D11_X 93 | ldy D11_Y 94 | jmp d11_write_at 95 | .dont: 96 | rts 97 | 98 | d11_inc_neighbors: 99 | ldx D11_X 100 | dex 101 | stx D11_NX 102 | inx 103 | inx 104 | inx 105 | stx D11_EX 106 | ldy D11_Y 107 | dey 108 | sty D11_NY 109 | iny 110 | iny 111 | iny 112 | sty D11_EY 113 | ; 114 | .next_tile: 115 | ldy D11_NY 116 | ldx D11_NX 117 | cpy D11_Y 118 | bne .not_self 119 | cpx D11_X 120 | bne .not_self 121 | jmp .dont_inc 122 | .not_self: 123 | jsr d11_read_at 124 | sta D11_Tmp 125 | and #$80 126 | bne .dont_inc 127 | inc D11_Tmp 128 | lda D11_Tmp 129 | ldy D11_NY 130 | ldx D11_NX 131 | jsr d11_write_at 132 | .dont_inc: 133 | ldx D11_NX 134 | inx 135 | stx D11_NX 136 | cpx D11_EX 137 | bmi .next_tile 138 | ldx D11_X 139 | dex 140 | stx D11_NX 141 | ldy D11_NY 142 | iny 143 | sty D11_NY 144 | cpy D11_EY 145 | beq .donedone 146 | jmp .next_tile 147 | .donedone: 148 | rts 149 | 150 | d11_light: 151 | jsr d11_read_at 152 | sta D11_Tmp 153 | and #$80 154 | bne .continue 155 | lda D11_Tmp 156 | cmp #10 157 | bmi .continue 158 | inc D11_NumLit 159 | jsr d11_inc_neighbors 160 | ldx D11_X 161 | ldy D11_Y 162 | lda #$80 163 | jmp d11_write_at 164 | .continue: 165 | rts 166 | 167 | d11_reset_lit: 168 | jsr d11_read_at 169 | sta D11_Tmp 170 | cmp #$80 171 | bne .nothing 172 | inc D11_NumLitStep 173 | ldx D11_X 174 | ldy D11_Y 175 | lda #0 176 | jmp d11_write_at 177 | .nothing: 178 | rts 179 | 180 | d11_do_step: 181 | lda #0 182 | sta D11_NumLitStep 183 | macro_walk_board d11_inc_squid 184 | .next_pass: 185 | lda #0 186 | sta D11_NumLit 187 | macro_walk_board d11_light 188 | lda D11_NumLit 189 | beq .done 190 | jmp .next_pass 191 | .done: 192 | macro_walk_board d11_reset_lit 193 | rts 194 | 195 | day11_solve_a: 196 | lda #LOW(day11_input) 197 | sta INPUT 198 | lda #HIGH(day11_input) 199 | sta INPUT+1 200 | macro_walk_board d11_init_board 201 | .next_step: 202 | jsr d11_do_step 203 | inc D11_Step 204 | bne .no_high 205 | inc D11_Step+1 206 | .no_high: 207 | lda D11_NumLitStep 208 | cmp #(10*10) 209 | bne .not_all_bois 210 | tmm16 D11_ScoreB, D11_Step 211 | rts 212 | .not_all_bois: 213 | macro_add16 D11_NumLitAll, D11_NumLitStep 214 | lda D11_Step 215 | cmp #100 216 | bne .next_100 217 | tmm16 Result, D11_NumLitAll 218 | .next_100: 219 | jmp .next_step 220 | 221 | day11_solve_b: 222 | tmm16 Result, D11_ScoreB 223 | rts 224 | -------------------------------------------------------------------------------- /day11_input.asm: -------------------------------------------------------------------------------- 1 | day11_input: 2 | db 2,2,3,8,5,1,8,6,1,4 3 | db 4,5,5,2,3,8,8,5,5,3 4 | db 2,5,6,2,1,2,1,1,4,3 5 | db 2,6,6,6,6,8,5,3,3,7 6 | db 7,5,7,5,5,1,8,7,8,4 7 | db 3,5,7,2,5,3,4,8,7,1 8 | db 8,4,1,1,7,1,8,2,8,3 9 | db 7,7,4,2,6,6,8,3,8,5 10 | db 1,2,3,5,1,3,3,2,3,1 11 | db 2,5,4,6,1,6,5,3,4,5 12 | day11_input_end: 13 | -------------------------------------------------------------------------------- /day12-a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pellsson/aoc2021/e71a765ea4cd3293ac239f629dc87f45888fe470/day12-a.png -------------------------------------------------------------------------------- /day12-b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pellsson/aoc2021/e71a765ea4cd3293ac239f629dc87f45888fe470/day12-b.png -------------------------------------------------------------------------------- /day12.asm: -------------------------------------------------------------------------------- 1 | INPUT .equ WORK 2 | D12_Name .equ WORK+2 ; until WORK+8? 3 | D12_NameOff .equ WORK+$10 4 | D12_LeftId .equ WORK+$11 5 | D12_RightId .equ WORK+$12 6 | D12_Index .equ WORK+$13 7 | D12_P .equ WORK+$14 8 | D12_Tmp .equ WORK+$15 9 | D12_SC .equ WORK+$17 10 | D12_SV .equ WORK+$18 11 | D12_IsB .equ WORK+$19 12 | D12_IsTwice .equ WORK+$1A 13 | D12_Prog .equ WORK+$1B 14 | D12_GraphSize .equ WORK+$20 15 | D12_Current .equ WORK+$22 16 | D12_Graph .equ $6000 17 | D12_StackCurrent .equ $6100 18 | D12_StackVisited .equ $6180 19 | 20 | D12_START_OFF .equ $10 21 | D12_END_OFF .equ $20 22 | 23 | ; idx, name[7], 24 | d12_start_graph: 25 | ; id 26 | db $00 27 | ; name 28 | db "invalid" 29 | ; links 30 | db $00, $00, $00, $00, $00, $00, $00, $00 31 | ; id 32 | db D12_START_OFF 33 | ; name 34 | db "start" 35 | db $00, $00 36 | ; links 37 | db $00, $00, $00, $00, $00, $00, $00, $00 38 | ; id 39 | db D12_END_OFF 40 | ; name 41 | db "end" 42 | db $00, $00, $00, $00 43 | ; links 44 | db $00, $00, $00, $00, $00, $00, $00, $00 45 | d12_start_graph_end: 46 | 47 | 48 | 49 | d12_get_id_by_name: 50 | lda #$10 51 | sta D12_P 52 | .new_search: 53 | tax 54 | ldy #0 55 | .next_char: 56 | lda D12_Graph+1, x 57 | cmp D12_Name, y 58 | bne .next_entry 59 | inx 60 | iny 61 | cpy D12_NameOff 62 | bne .next_char 63 | lda D12_P 64 | rts 65 | .next_entry: 66 | lda D12_P 67 | clc 68 | adc #$10 69 | sta D12_P 70 | cmp D12_GraphSize 71 | bne .new_search 72 | ; Cave is new, create it. 73 | tax 74 | sta D12_Graph,x 75 | clc 76 | adc #$10 77 | sta D12_GraphSize 78 | ldy #0 79 | .copy_name: 80 | lda D12_Name,y 81 | sta D12_Graph+1,x 82 | inx 83 | iny 84 | cpy D12_NameOff 85 | bne .copy_name 86 | lda D12_P 87 | rts 88 | 89 | d12_make_graph: 90 | lda #LOW(day12_input) 91 | sta INPUT 92 | lda #HIGH(day12_input) 93 | sta INPUT+1 94 | .next_word: 95 | lda #0 96 | sta D12_NameOff 97 | .next: 98 | lda INPUT 99 | cmp #LOW(day12_input_end) 100 | bne .not_end 101 | lda INPUT+1 102 | cmp #HIGH(day12_input_end) 103 | bne .not_end 104 | rts 105 | .not_end: 106 | jsr read_next 107 | cmp #'-' 108 | beq .left_full 109 | cmp #0 110 | beq .right_full 111 | ldx D12_NameOff 112 | sta D12_Name, x 113 | inc D12_NameOff 114 | jmp .next 115 | .left_full: 116 | jsr d12_get_id_by_name 117 | sta D12_LeftId 118 | jmp .next_word 119 | .right_full: 120 | jsr d12_get_id_by_name 121 | sta D12_RightId 122 | ldx D12_LeftId 123 | jsr d12_add_link 124 | lda D12_LeftId 125 | ldx D12_RightId 126 | jsr d12_add_link 127 | jmp .next_word 128 | 129 | d12_add_link: 130 | sta D12_Tmp 131 | .find: 132 | lda D12_Graph+$8,x 133 | beq .found_free 134 | inx 135 | bne .find 136 | .found_free: 137 | lda D12_Tmp 138 | sta D12_Graph+$8,x 139 | rts 140 | 141 | d12_visit_push: 142 | lda D12_Current 143 | ldx D12_SV 144 | sta D12_StackVisited,x 145 | inx 146 | stx D12_SV 147 | rts 148 | 149 | d12_visit_pop: 150 | ldx D12_SV 151 | dex 152 | ; pop (dont care about value, we are done here...) 153 | stx D12_SV 154 | rts 155 | 156 | d12_first_visit: 157 | jsr d12_visit_push 158 | jsr d12_walk_links 159 | ldx D12_SV 160 | jmp d12_visit_pop 161 | 162 | d12_walk_small: 163 | lda D12_Current 164 | ldx #0 165 | .check_next: 166 | cpx D12_SV 167 | beq .not_in_stack 168 | cmp D12_StackVisited, x 169 | beq .in_stack 170 | inx 171 | jmp .check_next 172 | .not_in_stack: 173 | jmp d12_first_visit 174 | .in_stack: 175 | cmp #D12_START_OFF 176 | bne .not_start 177 | rts 178 | .not_start: 179 | lda D12_IsB 180 | bne .is_b 181 | rts 182 | .is_b: 183 | lda D12_IsTwice 184 | beq .not_twice 185 | rts 186 | .not_twice: 187 | inc D12_IsTwice 188 | jsr d12_visit_push 189 | jsr d12_walk_links 190 | jsr d12_visit_pop 191 | dec D12_IsTwice 192 | rts 193 | 194 | d12_walk_links: 195 | ldx D12_Current 196 | .next_link: 197 | lda D12_Graph+8,x ; next link 198 | bne .not_done 199 | rts 200 | .not_done: 201 | pha 202 | inx 203 | txa 204 | ldy D12_SC 205 | sta D12_StackCurrent, y 206 | iny 207 | sty D12_SC 208 | pla 209 | sta D12_Current 210 | jsr d12_walk_graph 211 | ldy D12_SC 212 | dey 213 | lda D12_StackCurrent,y 214 | tax 215 | sty D12_SC 216 | jmp .next_link 217 | 218 | d12_log_prog: 219 | lda Result+1 220 | and #$E0 221 | cmp D12_Prog 222 | bne .update 223 | rts 224 | .update: 225 | sta D12_Prog 226 | lda #0 227 | sta PrintColor 228 | macro_putstr_inline " Found #" 229 | inc PrintColor 230 | lda Result+2 231 | jsr _puthex 232 | lda Result+1 233 | jsr _puthex 234 | lda Result+0 235 | jsr _puthex 236 | jmp wait_flush 237 | 238 | d12_walk_graph: 239 | lda D12_Current 240 | cmp #D12_END_OFF 241 | bne .not_end 242 | macro_inc32 Result 243 | lda D12_IsB 244 | beq .not_b 245 | jmp d12_log_prog 246 | .not_b: 247 | rts 248 | .not_end: 249 | tax 250 | lda D12_Graph+1,x ; first char 251 | and #$20 252 | beq .isuppercase 253 | jmp d12_walk_small 254 | .isuppercase: 255 | jmp d12_walk_links 256 | 257 | day12_solve: 258 | lda #0 259 | ldx #0 260 | .more_reset: 261 | sta D12_Graph, x 262 | sta D12_StackCurrent, x 263 | inx 264 | bne .more_reset 265 | .not_end: 266 | lda d12_start_graph, x 267 | sta D12_Graph, x 268 | inx 269 | cpx #(d12_start_graph_end-d12_start_graph) 270 | bne .not_end 271 | lda #(d12_start_graph_end-d12_start_graph) 272 | sta D12_GraphSize 273 | jsr d12_make_graph 274 | lda #D12_START_OFF 275 | sta D12_Current 276 | jmp d12_walk_graph 277 | 278 | day12_solve_a: 279 | jmp day12_solve 280 | day12_solve_b: 281 | inc D12_IsB 282 | jmp day12_solve -------------------------------------------------------------------------------- /day12_input.asm: -------------------------------------------------------------------------------- 1 | day12_input: 2 | db "qi-UD", 0 3 | db "jt-br", 0 4 | db "wb-TF", 0 5 | db "VO-aa", 0 6 | db "UD-aa", 0 7 | db "br-end", 0 8 | db "end-HA", 0 9 | db "qi-br", 0 10 | db "br-HA", 0 11 | db "UD-start", 0 12 | db "TF-qi", 0 13 | db "br-hf", 0 14 | db "VO-hf", 0 15 | db "start-qi", 0 16 | db "end-aa", 0 17 | db "hf-HA", 0 18 | db "hf-UD", 0 19 | db "aa-hf", 0 20 | db "TF-hf", 0 21 | db "VO-start", 0 22 | db "wb-aa", 0 23 | db "UD-wb", 0 24 | db "KX-wb", 0 25 | db "qi-VO", 0 26 | db "br-TF", 0 27 | day12_input_end: -------------------------------------------------------------------------------- /day13-a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pellsson/aoc2021/e71a765ea4cd3293ac239f629dc87f45888fe470/day13-a.png -------------------------------------------------------------------------------- /day13-b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pellsson/aoc2021/e71a765ea4cd3293ac239f629dc87f45888fe470/day13-b.png -------------------------------------------------------------------------------- /day13.asm: -------------------------------------------------------------------------------- 1 | INPUT .equ WORK 2 | D13_TmpLo .equ WORK+$2 3 | D13_TmpHi .equ WORK+$3 4 | D13_AddX .equ WORK+$4 ; and 5 5 | D13_AddY .equ WORK+$6 ; and 7 6 | D13_W .equ WORK+$10 ; and 11 7 | D13_H .equ WORK+$12 ; and 13 8 | D13_X .equ WORK+$14 ; and 15 9 | D13_Y .equ WORK+$16 ; and 17 10 | D13_Fold .equ WORK+$18 11 | D13_FoldAt .equ WORK+$1A 12 | D13_FoldPtr .equ WORK+$1C 13 | D13_Dots .equ $6000 14 | 15 | ; macro_fold major_coor, dimension 16 | macro_fold .macro 17 | macro_sub16_imm8 \2, 1 18 | macro_sub16 \2, D13_FoldAt 19 | lda #LOW(D13_Dots) 20 | sta INPUT 21 | lda #HIGH(D13_Dots) 22 | sta INPUT+1 23 | .skip\@: 24 | jsr read_next 25 | sta D13_X 26 | jsr read_next 27 | cmp #$ff 28 | bne .not_end\@ 29 | rts 30 | .not_end\@: 31 | sta D13_X+1 32 | jsr read_next 33 | sta D13_Y 34 | jsr read_next 35 | sta D13_Y+1 36 | cmp #$80 37 | beq .skip\@ 38 | lda \1 39 | cmp D13_FoldAt 40 | bne .not_in_crest\@ 41 | lda \1+1 42 | cmp D13_FoldAt 43 | bne .not_in_crest\@ 44 | ; in crest, kill. 45 | jsr d13_delete_last 46 | jmp .skip\@ 47 | .not_in_crest\@: 48 | macro_is_less_u16 \1, D13_FoldAt, .skip\@ 49 | macro_sub16 \1, D13_FoldAt 50 | macro_sub16_out \1, \2, \1 51 | jsr add_dot 52 | jmp .skip\@ 53 | .endm 54 | 55 | d13_update_dimensions: 56 | lda #0 57 | sta D13_W 58 | sta D13_W+1 59 | sta D13_H 60 | sta D13_H+1 61 | lda #LOW(D13_Dots) 62 | sta INPUT 63 | lda #HIGH(D13_Dots) 64 | sta INPUT+1 65 | .read_more: 66 | jsr read_next 67 | sta D13_X 68 | jsr read_next 69 | sta D13_X+1 70 | jsr read_next 71 | sta D13_Y 72 | jsr read_next 73 | sta D13_Y+1 74 | lda D13_X+1 75 | cmp #$FF 76 | bne .not_at_end 77 | rts 78 | .not_at_end: 79 | cmp #$80 80 | beq .read_more 81 | macro_add16_imm8 D13_X, 1 82 | macro_max_u16 D13_W, D13_W, D13_X 83 | macro_add16_imm8 D13_Y, 1 84 | macro_max_u16 D13_H, D13_H, D13_Y 85 | jmp .read_more 86 | 87 | calc_score_a: 88 | lda #LOW(D13_Dots) 89 | sta INPUT 90 | lda #HIGH(D13_Dots) 91 | sta INPUT+1 92 | .count_next: 93 | jsr read_next 94 | jsr read_next 95 | cmp #$FF 96 | beq .done 97 | jsr read_next 98 | jsr read_next 99 | cmp #$80 100 | beq .count_next 101 | macro_add16_imm8 Result, 1 102 | jmp .count_next 103 | .done: 104 | rts 105 | 106 | day13_solve_a: 107 | macro_memcpy day13_input, day13_dots_end, D13_Dots ; Why are the params backwards... wtf did i do here...? 108 | lda #$FF 109 | sta [Dst], Y 110 | iny 111 | sta [Dst], Y 112 | jsr d13_update_dimensions 113 | lda #LOW(day13_folds) 114 | sta D13_FoldPtr 115 | lda #HIGH(day13_folds) 116 | sta D13_FoldPtr+1 117 | ldy #0 118 | sty D13_Fold 119 | .next_fold: 120 | ldy D13_Fold 121 | cpy #3 122 | bne .not_first 123 | jsr calc_score_a 124 | ldy D13_Fold 125 | .not_first: 126 | cpy #(day13_input_end-day13_folds) 127 | bne .not_done 128 | rts 129 | .not_done: 130 | lda [D13_FoldPtr], y 131 | pha 132 | iny 133 | lda [D13_FoldPtr], y 134 | sta D13_FoldAt 135 | iny 136 | lda [D13_FoldPtr], y 137 | sta D13_FoldAt+1 138 | iny 139 | sty D13_Fold 140 | pla 141 | cmp #'y' 142 | beq .do_fold_horizontal 143 | jsr fold_vertically 144 | jmp .next_fold 145 | .do_fold_horizontal: 146 | jsr fold_horizontal 147 | jmp .next_fold 148 | 149 | fold_horizontal: 150 | macro_fold D13_Y, D13_H 151 | ; returns 152 | 153 | fold_vertically: 154 | macro_fold D13_X, D13_W 155 | ; returns when its done 156 | 157 | d13_delete_last: 158 | lda #$80 159 | sta D13_AddX 160 | sta D13_AddX+1 161 | sta D13_AddY 162 | sta D13_AddY+1 163 | d13_overwrite_current: 164 | macro_sub16_imm8 INPUT, 4 165 | ldy #0 166 | lda D13_AddX 167 | sta [INPUT], Y 168 | jsr skip_next 169 | lda D13_AddX+1 170 | sta [INPUT], Y 171 | jsr skip_next 172 | lda D13_AddY 173 | sta [INPUT], Y 174 | jsr skip_next 175 | lda D13_AddY+1 176 | sta [INPUT], Y 177 | jmp skip_next 178 | 179 | check_if_equal: 180 | lda D13_X 181 | cmp D13_AddX 182 | bne .not_eq 183 | lda D13_X+1 184 | cmp D13_AddX+1 185 | bne .not_eq 186 | lda D13_Y 187 | cmp D13_AddY 188 | bne .not_eq 189 | lda D13_Y+1 190 | cmp D13_AddY+1 191 | bne .not_eq 192 | .not_eq: 193 | rts 194 | 195 | add_dot: 196 | jsr d13_delete_last 197 | tmm16 D13_TmpLo, INPUT 198 | lda #LOW(D13_Dots) 199 | sta INPUT 200 | lda #HIGH(D13_Dots) 201 | sta INPUT+1 202 | .next: 203 | jsr read_next 204 | sta D13_AddX 205 | jsr read_next 206 | sta D13_AddX+1 207 | jsr read_next 208 | sta D13_AddY 209 | jsr read_next 210 | sta D13_AddY+1 211 | lda D13_AddX+1 212 | cmp #$FF 213 | bne .not_end 214 | ; Does not already exist, we need to add the new value. 215 | tmm16 D13_AddX, D13_X 216 | tmm16 D13_AddY, D13_Y 217 | tmm16 INPUT, D13_TmpLo 218 | jmp d13_overwrite_current 219 | .already_exists: 220 | tmm16 INPUT, D13_TmpLo 221 | rts 222 | .not_end: 223 | jsr check_if_equal 224 | beq .already_exists 225 | jmp .next 226 | 227 | write_dot: 228 | lda #LOW(D13_Dots) 229 | sta INPUT 230 | lda #HIGH(D13_Dots) 231 | sta INPUT+1 232 | .next: 233 | jsr read_next 234 | sta D13_AddX 235 | jsr read_next 236 | sta D13_AddX+1 237 | jsr read_next 238 | sta D13_AddY 239 | jsr read_next 240 | sta D13_AddY+1 241 | lda D13_AddX+1 242 | cmp #$FF 243 | bne .not_end 244 | lda #'.' 245 | jmp _putchar 246 | .not_end: 247 | jsr check_if_equal 248 | bne .next 249 | lda #'#' 250 | jmp _putchar 251 | 252 | 253 | macro_print_block .macro 254 | lda #\1 255 | sta D13_X 256 | lda #0 257 | sta D13_Y 258 | sta D13_Y+1 259 | sta D13_X+1 260 | .next_x\@: 261 | lda D13_X 262 | cmp #\2 263 | bcs .next_row\@ 264 | jsr write_dot 265 | inc D13_X 266 | jmp .next_x\@ 267 | .next_row\@: 268 | jsr wait_flush 269 | lda #\1 270 | sta D13_X 271 | ldx D13_Y 272 | inx 273 | stx D13_Y 274 | cpx #6 275 | bne .next_x\@ 276 | .endm 277 | 278 | day13_solve_b: 279 | macro_print_block 0, 20 280 | jsr wait_flush 281 | macro_print_block 20, 40 282 | jmp wait_flush 283 | -------------------------------------------------------------------------------- /day14.asm: -------------------------------------------------------------------------------- 1 | INPUT .equ WORK 2 | D14_PtrCurrent .equ WORK+$2 ; and 3 3 | D14_C .equ WORK+$4 ; 5,6,7,8,9,a,b 4 | D14_Find .equ WORK+$10 ; and 5 5 | D14_CX .equ WORK+$18 ; => $20 6 | 7 | D14_E .equ WORK+$20 8 | D14_P .equ WORK+$22 ; And 23 9 | 10 | D14_Iter .equ WORK+$24 ; And 25 11 | 12 | D14_PassLeft .equ WORK+$28 13 | 14 | D14_Min .equ WORK+$30 15 | D14_Max .equ WORK+$38 16 | 17 | D14_Pairs .equ $6000 18 | D14_PairsCopy .equ $6800 19 | D14_Elems .equ $7000 20 | 21 | d14_get_pair_copy: 22 | lda #LOW(D14_PairsCopy) 23 | sta D14_PtrCurrent 24 | lda #HIGH(D14_PairsCopy) 25 | sta D14_PtrCurrent+1 26 | jmp d14_get_any 27 | 28 | d14_get_pair: 29 | lda #LOW(D14_Pairs) 30 | sta D14_PtrCurrent 31 | lda #HIGH(D14_Pairs) 32 | sta D14_PtrCurrent+1 33 | jmp d14_get_any 34 | 35 | d14_get_element: 36 | lda #0 37 | sta D14_Find+1 38 | lda #LOW(D14_Elems) 39 | sta D14_PtrCurrent 40 | lda #HIGH(D14_Elems) 41 | sta D14_PtrCurrent+1 42 | d14_get_any: 43 | ldy #0 44 | lda [D14_PtrCurrent], Y 45 | bne .not_end 46 | ; New pair, insert it. 47 | lda D14_Find 48 | sta [D14_PtrCurrent], Y 49 | iny 50 | lda D14_Find+1 51 | sta [D14_PtrCurrent], Y 52 | jmp .return_this 53 | .not_end: 54 | cmp D14_Find 55 | bne .next 56 | iny 57 | lda [D14_PtrCurrent], Y 58 | cmp D14_Find+1 59 | bne .next 60 | .return_this: 61 | iny 62 | macro_add16_imm8 D14_PtrCurrent, 2 63 | rts 64 | .next: 65 | macro_add16_imm8 D14_PtrCurrent, 10 ;2+8 66 | jmp d14_get_any 67 | 68 | d14_load_current: 69 | ldy #0 70 | lda [D14_PtrCurrent], Y 71 | iny 72 | sta D14_C+0 73 | lda [D14_PtrCurrent], Y 74 | iny 75 | sta D14_C+1 76 | lda [D14_PtrCurrent], Y 77 | iny 78 | sta D14_C+2 79 | lda [D14_PtrCurrent], Y 80 | iny 81 | sta D14_C+3 82 | lda [D14_PtrCurrent], Y 83 | iny 84 | sta D14_C+4 85 | lda [D14_PtrCurrent], Y 86 | iny 87 | sta D14_C+5 88 | lda [D14_PtrCurrent], Y 89 | iny 90 | sta D14_C+6 91 | lda [D14_PtrCurrent], Y 92 | iny 93 | sta D14_C+7 94 | rts 95 | 96 | d14_save_current: 97 | ldy #0 98 | lda D14_C 99 | sta [D14_PtrCurrent],Y 100 | iny 101 | lda D14_C+1 102 | sta [D14_PtrCurrent],Y 103 | iny 104 | lda D14_C+2 105 | sta [D14_PtrCurrent],Y 106 | iny 107 | lda D14_C+3 108 | sta [D14_PtrCurrent],Y 109 | iny 110 | lda D14_C+4 111 | sta [D14_PtrCurrent],Y 112 | iny 113 | lda D14_C+5 114 | sta [D14_PtrCurrent],Y 115 | iny 116 | lda D14_C+6 117 | sta [D14_PtrCurrent],Y 118 | iny 119 | lda D14_C+7 120 | sta [D14_PtrCurrent],Y 121 | rts 122 | 123 | d14_current_inc32: 124 | jsr d14_load_current 125 | macro_inc32 D14_C 126 | jmp d14_save_current 127 | 128 | d14_get_combined_element: 129 | lda #LOW(day14_poly) 130 | sta INPUT 131 | lda #HIGH(day14_poly) 132 | sta INPUT+1 133 | .read: 134 | jsr read_next 135 | cmp D14_Find 136 | bne .not_skip_2 137 | jsr read_next 138 | cmp D14_Find+1 139 | bne .not_skip_1 140 | jmp read_next 141 | .not_skip_2: 142 | jsr skip_next 143 | .not_skip_1: 144 | jsr skip_next 145 | jmp .read 146 | 147 | d14_add_cx: 148 | jsr d14_load_current 149 | macro_add64 D14_C, D14_CX 150 | jmp d14_save_current 151 | 152 | d14_initialize: 153 | macro_memset_pb $6000, 0, $2000 ; all ex-ram memset(0) 154 | ldx #0 155 | .init_more: 156 | lda day14_input, x 157 | sta D14_Find 158 | lda day14_input+1, x 159 | sta D14_Find+1 160 | jsr d14_get_pair 161 | jsr d14_current_inc32 162 | jsr d14_get_element 163 | jsr d14_current_inc32 164 | inx 165 | cpx #(day14_poly-day14_input-1) 166 | bne .init_more 167 | ; Count last element of start config 168 | lda day14_input, x 169 | sta D14_Find 170 | jsr d14_get_element 171 | jmp d14_current_inc32 172 | 173 | d14_step: 174 | ; Solve. 175 | macro_memcpy D14_Pairs, D14_Pairs+0x400, D14_PairsCopy ; Again, the argument list is reversed :( so dumb. I should just fix it... 176 | lda #LOW(D14_PairsCopy) 177 | sta D14_Iter 178 | lda #HIGH(D14_PairsCopy) 179 | sta D14_Iter+1 180 | .next: 181 | ldy #0 182 | lda [D14_Iter],Y 183 | bne .not_done 184 | rts 185 | .not_done: 186 | sta D14_Find 187 | iny 188 | lda [D14_Iter],Y 189 | sta D14_Find+1 190 | macro_add16_imm8 D14_Iter, 10 ; 2+8 191 | tmm16 D14_P, D14_Find 192 | jsr d14_get_pair_copy 193 | jsr d14_load_current 194 | tmm64 D14_CX, D14_C 195 | ; Translate to !copy array 196 | macro_sub16_imm16 D14_PtrCurrent, D14_PairsCopy-D14_Pairs 197 | jsr d14_load_current 198 | macro_sub64 D14_C, D14_CX 199 | jsr d14_save_current 200 | jsr d14_get_combined_element 201 | sta D14_E 202 | sta D14_Find 203 | jsr d14_get_element 204 | jsr d14_add_cx 205 | lda D14_P 206 | sta D14_Find 207 | lda D14_E 208 | sta D14_Find+1 209 | jsr d14_get_pair 210 | jsr d14_add_cx 211 | lda D14_E 212 | sta D14_Find 213 | lda D14_P+1 214 | sta D14_Find+1 215 | jsr d14_get_pair 216 | jsr d14_add_cx 217 | jmp .next 218 | 219 | d14_find_minmax: 220 | lda #$FF 221 | sta D14_Min+7 ; MSB 222 | lda #LOW(D14_Elems) 223 | sta D14_Iter 224 | lda #HIGH(D14_Elems) 225 | sta D14_Iter+1 226 | .next: 227 | ldy #0 228 | lda [D14_Iter], Y 229 | bne .not_end 230 | rts 231 | .not_end: 232 | tmm64 MathLhs, D14_Min 233 | iny 234 | iny 235 | lda [D14_Iter], Y 236 | sta MathRhs 237 | iny 238 | lda [D14_Iter], Y 239 | sta MathRhs+1 240 | iny 241 | lda [D14_Iter], Y 242 | sta MathRhs+2 243 | iny 244 | lda [D14_Iter], Y 245 | sta MathRhs+3 246 | iny 247 | lda [D14_Iter], Y 248 | sta MathRhs+4 249 | iny 250 | lda [D14_Iter], Y 251 | sta MathRhs+5 252 | iny 253 | lda [D14_Iter], Y 254 | sta MathRhs+6 255 | iny 256 | lda [D14_Iter], Y 257 | sta MathRhs+7 258 | jsr math_min64 259 | tmm64 D14_Min, MathOut 260 | tmm64 MathLhs, D14_Max 261 | jsr math_max64 262 | tmm64 D14_Max, MathOut 263 | macro_add16_imm8 D14_Iter, 10 264 | jmp .next 265 | 266 | day14_solve_a: 267 | jsr d14_initialize 268 | lda #10 269 | sta D14_PassLeft 270 | .more: 271 | jsr d14_step 272 | dec D14_PassLeft 273 | bne .more 274 | jsr d14_find_minmax 275 | macro_sub64_out Result, D14_Max, D14_Min 276 | rts 277 | 278 | day14_solve_b: 279 | jsr d14_initialize 280 | lda #40 281 | sta D14_PassLeft 282 | .more: 283 | jsr d14_step 284 | dec D14_PassLeft 285 | bne .more 286 | jsr d14_find_minmax 287 | macro_sub64_out Result, D14_Max, D14_Min 288 | rts 289 | 290 | -------------------------------------------------------------------------------- /day14_input.asm: -------------------------------------------------------------------------------- 1 | day14_input: 2 | db "NNCB" 3 | day14_poly: 4 | db 'C','H','B' 5 | db 'H','H','N' 6 | db 'C','B','H' 7 | db 'N','H','C' 8 | db 'H','B','C' 9 | db 'H','C','B' 10 | db 'H','N','C' 11 | db 'N','N','C' 12 | db 'B','H','H' 13 | db 'N','C','B' 14 | db 'N','B','B' 15 | db 'B','N','B' 16 | db 'B','B','N' 17 | db 'B','C','B' 18 | db 'C','C','N' 19 | db 'C','N','C' 20 | day14_input_end: 21 | -------------------------------------------------------------------------------- /day2.asm: -------------------------------------------------------------------------------- 1 | INPUT .equ WORK 2 | SAVED_SEQUENCE .equ WORK+$4 3 | Pos .equ WORK+$8 4 | Depth .equ WORK+$C 5 | Aim .equ WORK+$10 6 | 7 | _read_next: 8 | ldy #0 9 | lda [INPUT], Y 10 | inc INPUT 11 | bne .no_high 12 | inc INPUT+1 13 | .no_high: 14 | rts 15 | 16 | day2_pass_a: 17 | jsr read_next 18 | tax 19 | jsr read_next 20 | sta MathRhs 21 | cpx #'f' 22 | beq .forward 23 | cpx #'d' 24 | beq .down 25 | ; up 26 | tmm32 MathLhs, Depth 27 | jsr math_sub32 28 | tmm32 Depth, MathOut 29 | rts 30 | .forward: 31 | tmm32 MathLhs, Pos 32 | jsr math_add32 33 | tmm32 Pos, MathOut 34 | rts 35 | .down: 36 | tmm32 MathLhs, Depth 37 | jsr math_add32 38 | tmm32 Depth, MathOut 39 | rts 40 | 41 | day2_solve_a: 42 | lda #LOW(day2_input_a) 43 | sta INPUT 44 | lda #HIGH(day2_input_a) 45 | sta INPUT+1 46 | .keep_solving: 47 | jsr day2_pass_a 48 | lda #LOW(day2_input_a_end) 49 | cmp INPUT 50 | bne .keep_solving 51 | lda #HIGH(day2_input_a_end) 52 | cmp INPUT+1 53 | bne .keep_solving 54 | day2_calc_result: 55 | tmm32 MathLhs, Pos 56 | tmm32 MathRhs, Depth 57 | jsr math_mul32 58 | tmm32 Result, MathOut 59 | rts 60 | 61 | day2_pass_b: 62 | jsr read_next 63 | tax 64 | jsr read_next 65 | sta MathRhs 66 | lda #0 67 | sta MathRhs+1 68 | sta MathRhs+2 69 | sta MathRhs+3 70 | cpx #'f' 71 | beq .forward 72 | cpx #'d' 73 | bne .up 74 | jmp .down 75 | .up: 76 | tmm32 MathLhs, Aim 77 | jsr math_sub32 78 | tmm32 Aim, MathOut ; aim -= v 79 | rts 80 | .forward: 81 | tmm32 MathLhs, Pos 82 | jsr math_add32 83 | tmm32 Pos, MathOut ; pos += v 84 | tmm32 MathLhs, Aim 85 | jsr math_mul32 86 | tmm32 MathRhs, MathOut ; tmp = aim*v 87 | tmm32 MathLhs, Depth 88 | jsr math_add32 89 | tmm32 Depth, MathOut 90 | rts 91 | .down: 92 | tmm32 MathLhs, Aim 93 | jsr math_add32 94 | tmm32 Aim, MathOut ; aim += v 95 | rts 96 | 97 | day2_solve_b: 98 | lda #LOW(day2_input_a) ; Same input again (Thanks :)) 99 | sta INPUT 100 | lda #HIGH(day2_input_a) 101 | sta INPUT+1 102 | .keep_solving: 103 | jsr day2_pass_b 104 | lda #LOW(day2_input_a_end) 105 | cmp INPUT 106 | bne .keep_solving 107 | lda #HIGH(day2_input_a_end) 108 | cmp INPUT+1 109 | bne .keep_solving 110 | jmp day2_calc_result -------------------------------------------------------------------------------- /day3.asm: -------------------------------------------------------------------------------- 1 | INPUT .equ WORK 2 | HighMask .equ WORK+$4 3 | Diff .equ WORK+$6 ; and 7 4 | V .equ WORK+$8 5 | CountMask .equ WORK+$9 6 | IsHigh .equ WORK+$a 7 | Mask .equ WORK+$10 ; and 11 8 | G .equ WORK+$12 9 | Remaining .equ WORK+$14 ; and 15 10 | KeepValue .equ WORK+$16 11 | PtrHighByte .equ WORK+$18 ; and 19 12 | WantMany .equ WORK+$1A 13 | Oxygen .equ WORK+$20 ; and 21 14 | 15 | save_input_pos: 16 | lda INPUT 17 | sta PtrHighByte 18 | lda INPUT+1 19 | sta PtrHighByte+1 20 | rts 21 | 22 | filter_array: 23 | lda #0 24 | sta Remaining 25 | sta Remaining+1 26 | ; sty IsHigh 27 | ; stx CountMask 28 | .next: 29 | lda IsHigh 30 | beq .is_low 31 | jsr read_next ; lo 32 | sta TMP 33 | jsr save_input_pos ; input points to high 34 | jsr read_next ; hi 35 | sta V ; Value to check 36 | jmp .check_end 37 | .is_low: 38 | jsr read_next ; lo 39 | sta V ; Value to check 40 | jsr save_input_pos ; input points to high 41 | jsr read_next ; hi 42 | sta TMP 43 | .check_end: 44 | ; Check if the elment is deleted 45 | and #$80 46 | bne .next 47 | lda V 48 | ora TMP 49 | bne .count_next 50 | rts 51 | .count_next: 52 | lda CountMask 53 | and V 54 | cmp KeepValue 55 | beq .keep 56 | ldy #0 57 | lda #$80 58 | sta [PtrHighByte],Y 59 | jmp .next 60 | .keep: 61 | macro_add16_imm8 Remaining, 1 62 | jmp .next 63 | 64 | count_bits: 65 | sty IsHigh 66 | stx CountMask 67 | ldx #0 68 | stx Diff 69 | stx Diff+1 70 | .next: 71 | lda IsHigh 72 | beq .is_low 73 | jsr read_next ; lo 74 | sta TMP 75 | jsr read_next ; hi 76 | sta V ; Value to check 77 | jmp .check_end 78 | .is_low: 79 | jsr read_next ; lo 80 | sta V ; Value to check 81 | jsr read_next ; hi 82 | sta TMP 83 | .check_end: 84 | and #$80 85 | bne .next ; Ignore deleted values 86 | lda V 87 | ora TMP 88 | bne .count_next 89 | rts 90 | .count_next 91 | lda CountMask 92 | and V 93 | beq .clear 94 | ; set 95 | macro_add16_imm8 Diff, 1 96 | jmp .next 97 | .clear: 98 | macro_sub16_imm8 Diff, 1 99 | jmp .next 100 | 101 | next_mask: 102 | lda IsHigh 103 | beq .next_low 104 | lda Mask+1 105 | lsr a 106 | sta Mask+1 107 | bne .done 108 | lda #$80 109 | sta Mask 110 | rts 111 | .next_low: 112 | lda Mask 113 | lsr a 114 | sta Mask 115 | .done: 116 | rts 117 | 118 | day3_solve_a: 119 | lda #0 120 | sta G 121 | sta G+1 122 | sta Mask 123 | lda #8 124 | sta Mask+1 ; 0x800 125 | .next_bit: 126 | lda #LOW(day3_input) 127 | sta INPUT 128 | lda #HIGH(day3_input) 129 | sta INPUT+1 130 | 131 | ldy #1 132 | lda Mask+1 133 | bne .do_high 134 | lda Mask 135 | beq .done 136 | dey 137 | .do_high: 138 | tax 139 | jsr count_bits 140 | lda Diff+1 141 | bmi .not_counted 142 | bne .counted 143 | .check_zero: 144 | lda Diff 145 | beq .not_counted 146 | .counted: 147 | ; It is more prominently 1 than 0 in this position 148 | lda G 149 | ora Mask 150 | sta G 151 | lda G+1 152 | ora Mask+1 153 | sta G+1 154 | .not_counted: 155 | jsr next_mask 156 | jmp .next_bit 157 | .done: 158 | lda G 159 | sta MathRhs 160 | eor #$ff 161 | sta MathLhs 162 | lda G+1 163 | sta MathRhs+1 164 | eor #$f 165 | sta MathLhs+1 166 | jsr math_mul32 167 | jmp mathout_to_res 168 | 169 | solve_b: 170 | lda #0 171 | sta Mask 172 | lda #8 173 | sta Mask+1 ; 0x800 174 | macro_memcpy day3_input, day3_input_end, $6000 ; Array to RAM 175 | .next_pass: 176 | lda #LOW($6000) 177 | sta INPUT 178 | lda #HIGH($6000) 179 | sta INPUT+1 180 | ldy #1 181 | lda Mask+1 182 | bne .do_high 183 | lda Mask 184 | beq impossible 185 | dey 186 | .do_high: 187 | tax 188 | jsr count_bits 189 | jsr figure_filter 190 | lda #LOW($6000) 191 | sta INPUT 192 | lda #HIGH($6000) 193 | sta INPUT+1 194 | jsr filter_array 195 | lda Remaining+1 196 | bne .go_next_mask 197 | lda #$01 198 | cmp Remaining 199 | bne .go_next_mask 200 | rts 201 | 202 | .go_next_mask: 203 | jsr next_mask 204 | jmp .next_pass 205 | 206 | impossible: 207 | jmp impossible 208 | 209 | figure_filter: 210 | lda WantMany 211 | beq .want_few 212 | jmp filter_want_many 213 | .want_few: 214 | lda Diff+1 215 | bmi .more_zeros 216 | bne .more_ones 217 | lda Diff 218 | bne .more_ones 219 | lda #0 220 | sta KeepValue 221 | rts 222 | .more_zeros: 223 | lda CountMask 224 | sta KeepValue 225 | rts 226 | .more_ones: 227 | lda #0 228 | sta KeepValue 229 | rts 230 | 231 | filter_want_many: 232 | lda Diff+1 233 | bmi .more_zeros 234 | bne .more_ones 235 | lda Diff 236 | bne .more_ones 237 | lda CountMask 238 | sta KeepValue 239 | rts 240 | .more_zeros: 241 | lda #0 242 | sta KeepValue 243 | rts 244 | .more_ones: 245 | lda CountMask 246 | sta KeepValue 247 | rts 248 | 249 | find_remaining: 250 | lda #LOW($6000) 251 | sta INPUT 252 | lda #HIGH($6000) 253 | sta INPUT+1 254 | .keep_searching: 255 | jsr read_next 256 | sta TMP 257 | jsr read_next 258 | sta V 259 | and #$80 260 | bne .keep_searching 261 | rts 262 | 263 | day3_solve_b: 264 | lda #1 265 | sta WantMany 266 | jsr solve_b 267 | jsr find_remaining 268 | lda TMP 269 | sta Oxygen 270 | lda V 271 | sta Oxygen+1 272 | lda #0 273 | sta WantMany 274 | jsr solve_b 275 | jsr find_remaining 276 | lda TMP 277 | sta MathRhs 278 | lda V 279 | sta MathRhs+1 280 | lda Oxygen 281 | sta MathLhs 282 | lda Oxygen+1 283 | sta MathLhs+1 284 | jsr math_mul32 285 | jmp mathout_to_res 286 | -------------------------------------------------------------------------------- /day4.asm: -------------------------------------------------------------------------------- 1 | INPUT .equ WORK 2 | Number .equ WORK+3 3 | NumberPos .equ WORK+4 4 | BoardId .equ WORK+5 5 | Col .equ WORK+8 6 | Row .equ WORK+9 7 | BoardHead .equ WORK+$a ; and b 8 | UnmarkedSum .equ WORK+$c 9 | BoardIter .equ WORK+$10 ; and 11 10 | 11 | SolvedBoards .equ $6000 12 | BoardsData .equ $6100 13 | 14 | BOARD_SIZE .equ 5*5 15 | 16 | set_board_solved: 17 | ldx BoardId 18 | lda #1 19 | sta SolvedBoards, x 20 | rts 21 | 22 | check_full_row: 23 | ldy Col 24 | .next: 25 | lda [BoardHead], Y 26 | and #$80 27 | beq .not_solved 28 | iny 29 | iny 30 | iny 31 | iny 32 | iny 33 | cpy #25 34 | bmi .next 35 | jmp set_board_solved 36 | .not_solved: 37 | rts 38 | 39 | check_full_col: 40 | lda #0 41 | ldx Row 42 | .seek_more: 43 | dex 44 | bmi .row_found 45 | clc 46 | adc #5 47 | bne .seek_more ; always jumps 48 | .row_found: 49 | ldx #4 50 | tay 51 | .gogo: 52 | lda [BoardHead], Y 53 | and #$80 54 | beq .not_solved 55 | iny 56 | dex 57 | bpl .gogo 58 | jmp set_board_solved 59 | .not_solved: 60 | rts 61 | 62 | add_sum: 63 | sta MathRhs 64 | lda #0 65 | sta MathRhs+1 ; a bit paranoid but w/e 66 | lda UnmarkedSum 67 | sta MathLhs 68 | lda UnmarkedSum+1 69 | sta MathLhs+1 70 | jsr math_add16 71 | lda MathOut 72 | sta UnmarkedSum 73 | lda MathOut+1 74 | sta UnmarkedSum+1 75 | rts 76 | 77 | finalize_result: 78 | lda Number 79 | sta MathRhs 80 | lda #0 81 | sta MathRhs+1 82 | lda UnmarkedSum 83 | sta MathLhs 84 | lda UnmarkedSum+1 85 | sta MathLhs+1 86 | jsr math_mul32 87 | lda MathOut 88 | sta Result 89 | lda MathOut+1 90 | sta Result+1 91 | lda MathOut+2 92 | sta Result+2 93 | lda MathOut+3 94 | sta Result+3 95 | rts 96 | 97 | check_solved: 98 | lda #0 99 | sta UnmarkedSum 100 | sta UnmarkedSum+1 101 | jsr check_full_col 102 | jsr check_full_row 103 | ldx BoardId 104 | lda SolvedBoards, x 105 | beq .not_solved 106 | ldy #BOARD_SIZE-1 107 | .count_next: 108 | lda [BoardHead], Y 109 | and #$80 110 | bne .dont_count 111 | lda [BoardHead], Y 112 | jsr add_sum 113 | .dont_count: 114 | dey 115 | bpl .count_next 116 | jmp finalize_result 117 | .not_solved: 118 | rts 119 | 120 | ball_picked_board: 121 | lda INPUT 122 | sta BoardHead 123 | lda INPUT+1 124 | sta BoardHead+1 125 | lda #0 126 | sta Col 127 | sta Row 128 | .find_number: 129 | jsr peek_next 130 | cmp Number 131 | bne .next_tile 132 | lda #$80 133 | ora [INPUT], Y 134 | sta [INPUT], Y 135 | jmp check_solved 136 | .next_tile: 137 | jsr skip_next 138 | ldx Col 139 | inx 140 | stx Col 141 | cpx #5 142 | bne .find_number 143 | ldx #0 144 | stx Col 145 | ldx Row 146 | inx 147 | stx Row 148 | cpx #5 149 | bne .find_number 150 | rts 151 | 152 | ball_picked: 153 | lda #LOW(BoardsData) 154 | sta BoardIter 155 | lda #HIGH(BoardsData) 156 | sta BoardIter+1 157 | ldx #0 158 | stx BoardId 159 | .next_board: 160 | lda SolvedBoards, x 161 | bne .inc_board 162 | lda BoardIter 163 | sta INPUT 164 | lda BoardIter+1 165 | sta INPUT+1 166 | jsr ball_picked_board 167 | .inc_board: 168 | macro_add16_imm8 BoardIter, BOARD_SIZE 169 | ldx BoardId 170 | inx 171 | stx BoardId 172 | cpx #((day4_boards_end-day4_boards)/BOARD_SIZE) 173 | bne .next_board 174 | rts 175 | 176 | day4_init: 177 | lda #0 178 | ldx #0 179 | .init_solved: 180 | sta SolvedBoards, x 181 | inx 182 | bne .init_solved 183 | macro_memcpy day4_boards, day4_boards_end, BoardsData 184 | ldx #0 185 | rts 186 | 187 | day4_solve_a: 188 | jsr day4_init 189 | .pick_next_number: 190 | lda day4_numbers, x 191 | sta Number 192 | stx NumberPos 193 | jsr ball_picked 194 | lda Result 195 | ora Result+1 196 | ora Result+2 197 | ora Result+3 198 | bne .done 199 | ldx NumberPos 200 | inx 201 | cpx #(day4_numbers_end-day4_numbers) 202 | bne .pick_next_number 203 | .done: 204 | rts 205 | 206 | day4_solve_b: 207 | jsr day4_init 208 | .pick_next_number: 209 | lda day4_numbers, x 210 | sta Number 211 | stx NumberPos 212 | jsr ball_picked 213 | ldx NumberPos 214 | inx 215 | cpx #(day4_numbers_end-day4_numbers) 216 | bne .pick_next_number 217 | .done: 218 | rts -------------------------------------------------------------------------------- /day5.asm: -------------------------------------------------------------------------------- 1 | INPUT .equ WORK 2 | D5_IncludeDiagonal .equ WORK+$2 3 | D5_GX .equ WORK+3 ; and 4 4 | D5_GY .equ WORK+5 ; and 6 5 | D5_Ptr .equ WORK+7 ; and 8 6 | 7 | D5_x0 .equ WORK+$10 ; and 11 8 | D5_y0 .equ WORK+$12 ; and 13 9 | D5_x1 .equ WORK+$14 ; and 15 10 | D5_y1 .equ WORK+$16 ; and 17 11 | 12 | D5_minx .equ WORK+$20 ; and 21 13 | D5_maxx .equ WORK+$22 ; and 23 14 | D5_miny .equ WORK+$24 ; and 25 15 | D5_maxy .equ WORK+$26 ; and 27 16 | D5_x .equ WORK+$28 ; and 29 17 | D5_y .equ WORK+$2A ; and 2B 18 | D5_relx .equ WORK+$2C ; and 2D 19 | 20 | D5_WindowLeft .equ WORK+$32 21 | D5_WindowPtr .equ WORK+$34 22 | 23 | D5_WINDOW_SIZE .equ 50 24 | D5_BOARD_SIZE .equ 1000 25 | 26 | d5_read_coords: 27 | jsr read_next 28 | sta D5_x0 29 | jsr read_next 30 | sta D5_x0+1 31 | jsr read_next 32 | sta D5_y0 33 | jsr read_next 34 | sta D5_y0+1 35 | jsr read_next 36 | sta D5_x1 37 | jsr read_next 38 | sta D5_x1+1 39 | jsr read_next 40 | sta D5_y1 41 | jsr read_next 42 | sta D5_y1+1 43 | rts 44 | 45 | d5_get_diagonal: 46 | lda D5_x0 47 | cmp D5_x1 48 | bne .not_same_x 49 | lda D5_x0+1 50 | cmp D5_x1+1 51 | beq .is_same 52 | .not_same_x: 53 | lda D5_y0 54 | cmp D5_y1 55 | bne .not_same 56 | lda D5_y0+1 57 | cmp D5_y1+1 58 | beq .is_same 59 | .not_same: 60 | lda #1 61 | rts 62 | .is_same: 63 | lda #0 64 | rts 65 | 66 | inc_tile: 67 | ; Relative Y already in MathOut 68 | macro_mul16_imm16 MathOut, D5_WINDOW_SIZE 69 | macro_add16 MathOut, D5_relx 70 | macro_add16_imm16 MathOut, $6000 71 | ldy #0 72 | lda [MathOut], Y 73 | clc 74 | adc #1 75 | sta [MathOut], Y 76 | rts 77 | 78 | inc_if_inside: 79 | macro_sub16_out D5_relx, D5_x, D5_GX 80 | lda D5_relx+1 81 | bne .too_far 82 | lda D5_relx 83 | cmp #D5_WINDOW_SIZE 84 | bcs .too_far 85 | macro_sub16_out MathOut, D5_y, D5_GY 86 | lda MathOut+1 87 | bne .too_far 88 | lda MathOut 89 | cmp #D5_WINDOW_SIZE 90 | bcs .too_far 91 | ; Within window, increment. 92 | jmp inc_tile 93 | .too_far: 94 | rts 95 | 96 | d5_solve_straight: 97 | macro_min_u16 D5_minx, D5_x0, D5_x1 98 | macro_max_u16 D5_maxx, D5_x0, D5_x1 99 | macro_min_u16 D5_miny, D5_y0, D5_y1 100 | macro_max_u16 D5_maxy, D5_y0, D5_y1 101 | tmm16 D5_x, D5_minx 102 | tmm16 D5_y, D5_miny 103 | macro_add16_imm8 D5_maxx, 1 104 | macro_add16_imm8 D5_maxy, 1 105 | .next_y: 106 | lda D5_y 107 | cmp D5_maxy 108 | bne .next_x 109 | lda D5_y+1 110 | cmp D5_maxy+1 111 | bne .next_x 112 | rts 113 | .next_x: 114 | jsr inc_if_inside 115 | macro_add16_imm8 D5_x, 1 116 | lda D5_x 117 | cmp D5_maxx 118 | bne .next_x 119 | lda D5_x+1 120 | cmp D5_maxx+1 121 | bne .next_x 122 | tmm16 D5_x, D5_minx 123 | macro_add16_imm8 D5_y, 1 124 | jmp .next_y 125 | 126 | d5_solve_diagonal: 127 | tmm16 D5_x, D5_x0 128 | tmm16 D5_y, D5_y0 129 | .next: 130 | lda D5_x 131 | cmp D5_x1 132 | bne .not_done 133 | lda D5_x+1 134 | cmp D5_x1+1 135 | bne .not_done 136 | jmp inc_if_inside 137 | .not_done: 138 | jsr inc_if_inside 139 | lda #$01 140 | sta MathRhs 141 | lda #$00 142 | sta MathRhs+1 143 | macro_is_less_u16 D5_x, D5_x1, .x_is_less 144 | lda #$ff 145 | sta MathRhs 146 | sta MathRhs+1 147 | .x_is_less: 148 | macro_add16 D5_x, MathRhs 149 | lda #$01 150 | sta MathRhs 151 | lda #$00 152 | sta MathRhs+1 153 | macro_is_less_u16 D5_y, D5_y1, .y_is_less 154 | lda #$ff 155 | sta MathRhs 156 | sta MathRhs+1 157 | .y_is_less: 158 | macro_add16 D5_y, MathRhs 159 | jmp .next 160 | 161 | d5_solve_window: 162 | macro_memset_pb $6000, $00, D5_WINDOW_SIZE * D5_WINDOW_SIZE 163 | ; Grid cleared 164 | lda #LOW(day5_input) 165 | sta INPUT 166 | lda #HIGH(day5_input) 167 | sta INPUT+1 168 | .next_line: 169 | lda #LOW(day5_input_end) 170 | cmp INPUT 171 | bne .not_end 172 | lda #HIGH(day5_input_end) 173 | cmp INPUT+1 174 | bne .not_end 175 | rts 176 | .not_end: 177 | jsr d5_read_coords 178 | jsr d5_get_diagonal 179 | beq .is_straight ; Hor & vert lines always included 180 | lda D5_IncludeDiagonal 181 | bne .is_diagonal 182 | beq .next_line 183 | .is_straight: 184 | jsr d5_solve_straight 185 | jmp .next_line 186 | .is_diagonal: 187 | jsr d5_solve_diagonal 188 | jmp .next_line 189 | 190 | d5_sum_window: 191 | lda #LOW($6000) 192 | sta D5_WindowPtr 193 | lda #HIGH($6000) 194 | sta D5_WindowPtr+1 195 | ldy #0 196 | .check_next: 197 | lda #LOW($6000 + D5_WINDOW_SIZE * D5_WINDOW_SIZE + 1) 198 | cmp D5_WindowPtr 199 | bne .add_more 200 | lda #HIGH($6000 + D5_WINDOW_SIZE * D5_WINDOW_SIZE + 1) 201 | cmp D5_WindowPtr+1 202 | bne .add_more 203 | rts 204 | .add_more: 205 | lda [D5_WindowPtr], Y 206 | cmp #2 207 | bmi .dont_count 208 | macro_add16_imm8 Result, 1 209 | .dont_count: 210 | inc D5_WindowPtr 211 | bne .check_next 212 | inc D5_WindowPtr+1 213 | jmp .check_next 214 | 215 | d5_log: 216 | lda #0 217 | sta PrintColor 218 | macro_putstr_inline " Window Done. Sum: " 219 | inc PrintColor 220 | lda Result+1 221 | jsr _puthex 222 | lda Result 223 | jsr _puthex 224 | jmp wait_flush 225 | 226 | day5_solve: 227 | lda #0 228 | sta D5_GX 229 | sta D5_GX+1 230 | sta D5_GY 231 | sta D5_GY+1 232 | .next_window: 233 | jsr d5_solve_window 234 | jsr d5_sum_window 235 | jsr d5_log 236 | macro_add16_imm8 D5_GX, D5_WINDOW_SIZE 237 | lda D5_GX 238 | cmp #LOW(D5_BOARD_SIZE) 239 | bne .next_window 240 | lda D5_GX+1 241 | cmp #HIGH(D5_BOARD_SIZE) 242 | bne .next_window 243 | lda #0 244 | sta D5_GX 245 | sta D5_GX+1 246 | macro_add16_imm8 D5_GY, D5_WINDOW_SIZE 247 | lda D5_GY 248 | cmp #LOW(D5_BOARD_SIZE) 249 | bne .next_window 250 | lda D5_GY+1 251 | cmp #HIGH(D5_BOARD_SIZE) 252 | bne .next_window 253 | rts 254 | 255 | day5_solve_a: 256 | jmp day5_solve 257 | day5_solve_b: 258 | inc D5_IncludeDiagonal 259 | jmp day5_solve 260 | -------------------------------------------------------------------------------- /day6.asm: -------------------------------------------------------------------------------- 1 | INPUT .equ WORK ; 2 | IsB .equ WORK+2 3 | 4 | d6_lookup_80: 5 | db $8D, $05, $00, $00, $00, $00, $00, $00 6 | db $79, $05, $00, $00, $00, $00, $00, $00 7 | db $A7, $04, $00, $00, $00, $00, $00, $00 8 | db $82, $04, $00, $00, $00, $00, $00, $00 9 | db $0A, $04, $00, $00, $00, $00, $00, $00 10 | db $B6, $03, $00, $00, $00, $00, $00, $00 11 | db $89, $03, $00, $00, $00, $00, $00, $00 12 | db $0B, $03, $00, $00, $00, $00, $00, $00 13 | db $00, $03, $00, $00, $00, $00, $00, $00 14 | 15 | d6_lookup_256: 16 | db $3C, $FE, $88, $8F, $01, $00, $00, $00 17 | db $A9, $92, $F4, $71, $01, $00, $00, $00 18 | db $7C, $FA, $CD, $4E, $01, $00, $00, $00 19 | db $4A, $82, $F8, $36, $01, $00, $00, $00 20 | db $8A, $93, $B2, $19, $01, $00, $00, $00 21 | db $49, $EE, $5D, $04, $01, $00, $00, $00 22 | db $2E, $75, $CA, $ED, $00, $00, $00, $00 23 | db $70, $D5, $8C, $D9, $00, $00, $00, $00 24 | db $DA, $B5, $D1, $C8, $00, $00, $00, $00 25 | 26 | day6_solve: 27 | lda #LOW(day6_input) 28 | sta INPUT 29 | lda #HIGH(day6_input) 30 | sta INPUT+1 31 | .gogo: 32 | jsr read_next 33 | cmp #$ff 34 | bne .add_more 35 | rts 36 | .add_more: 37 | asl a ; *= 2 38 | asl a ; *= 4 39 | asl a ; *= 8 40 | tax 41 | lda IsB 42 | bne .do_256 43 | clc 44 | lda d6_lookup_80, x 45 | adc Result 46 | sta Result 47 | lda d6_lookup_80+1, x 48 | adc Result+1 49 | sta Result+1 50 | lda d6_lookup_80+2, x 51 | adc Result+2 52 | sta Result+2 53 | lda d6_lookup_80+3, x 54 | adc Result+3 55 | sta Result+3 56 | lda d6_lookup_80+4, x 57 | adc Result+4 58 | sta Result+4 59 | lda d6_lookup_80+5, x 60 | adc Result+5 61 | sta Result+5 62 | lda d6_lookup_80+6, x 63 | adc Result+6 64 | sta Result+6 65 | lda d6_lookup_80+7, x 66 | adc Result+7 67 | sta Result+7 68 | jmp .gogo 69 | .do_256: 70 | clc 71 | lda d6_lookup_256, x 72 | adc Result 73 | sta Result 74 | lda d6_lookup_256+1, x 75 | adc Result+1 76 | sta Result+1 77 | lda d6_lookup_256+2, x 78 | adc Result+2 79 | sta Result+2 80 | lda d6_lookup_256+3, x 81 | adc Result+3 82 | sta Result+3 83 | lda d6_lookup_256+4, x 84 | adc Result+4 85 | sta Result+4 86 | lda d6_lookup_256+5, x 87 | adc Result+5 88 | sta Result+5 89 | lda d6_lookup_256+6, x 90 | adc Result+6 91 | sta Result+6 92 | lda d6_lookup_256+7, x 93 | adc Result+7 94 | sta Result+7 95 | jmp .gogo 96 | 97 | day6_solve_a: 98 | jmp day6_solve 99 | 100 | day6_solve_b: 101 | inc IsB 102 | jmp day6_solve 103 | 104 | -------------------------------------------------------------------------------- /day6_input.asm: -------------------------------------------------------------------------------- 1 | day6_input: 2 | db 1,2,1,3,2,1,1,5,1,4,1,2,1,4,3,3,5,1,1,3,5,3,4,5,5,4,3,1,1,4,3,1,5,2,5,2,4,1,1,1,1,1,1,1,4,1,4,4,4,1,4,4,1,4,2,1,1,1,1,3,5,4,3,3,5,4,1,3,1,1,2,1,1,1,4,1,2,5,2,3,1,1,1,2,1,5,1,1,1,4,4,4,1,5,1,2,3,2,2,2,1,1,4,3,1,4,4,2,1,1,5,1,1,1,3,1,2,1,1,1,1,4,5,5,2,3,4,2,1,1,1,2,1,1,5,5,3,5,4,3,1,3,1,1,5,1,1,4,2,1,3,1,1,4,3,1,5,1,1,3,4,2,2,1,1,2,1,1,2,1,3,2,3,1,4,5,1,1,4,3,3,1,1,2,2,1,5,2,1,3,4,5,4,5,5,4,3,1,5,1,1,1,4,4,3,2,5,2,1,4,3,5,1,3,5,1,3,3,1,1,1,2,5,3,1,1,3,1,1,1,2,1,5,1,5,1,3,1,1,5,4,3,3,2,2,1,1,3,4,1,1,1,1,4,1,3,1,5,1,1,3,1,1,1,1,2,2,4,4,4,1,2,5,5,2,2,4,1,1,4,2,1,1,5,1,5,3,5,4,5,3,1,1,1,2,3,1,2,1,1 3 | day6_input_end: 4 | db $ff -------------------------------------------------------------------------------- /day7.asm: -------------------------------------------------------------------------------- 1 | INPUT .equ WORK 2 | D7_Curr .equ WORK+2 ; and 3 3 | D7_CostIter .equ WORK+4 ; and 5 4 | D7_V .equ WORK+$10 ; 11,12,13 5 | D7_SmartCrab .equ WORK+$20 6 | d7_find_min: 7 | ; XXX this fails if the smallest number is the last number. 8 | ; should add some bounds-check... 9 | lda #$ff 10 | sta Result 11 | sta Result+1 12 | sta Result+2 13 | sta Result+3 14 | ldy #0 15 | lda #LOW($6000) 16 | sta INPUT 17 | lda #HIGH($6000) 18 | sta INPUT+1 19 | .next: 20 | jsr read_next 21 | sta D7_V 22 | jsr read_next 23 | sta D7_V+1 24 | jsr read_next 25 | sta D7_V+2 26 | jsr read_next 27 | sta D7_V+3 28 | cmp Result+3 29 | bcc .keep 30 | lda D7_V+2 31 | cmp Result+2 32 | bcc .keep 33 | lda D7_V+1 34 | cmp Result+1 35 | bcc .keep 36 | lda D7_V 37 | cmp Result 38 | bcc .keep 39 | rts 40 | .keep: 41 | tmm32 Result, D7_V 42 | jmp .next 43 | 44 | smartify: 45 | lda #0 46 | sta MathRhs+2 47 | sta MathRhs+3 48 | ; (n*(n+1)/2) 49 | lda MathLhs 50 | sta MathRhs 51 | lda MathLhs+1 52 | sta MathRhs+1 53 | macro_add16_imm8 MathLhs, 1 ; (n+1) 54 | jsr math_mul32 ; n*(n+1) 55 | tmm32 MathLhs, MathOut 56 | lsr MathLhs+3 57 | ror MathLhs+2 58 | ror MathLhs+1 59 | ror MathLhs ;n*(n+1)/2 60 | rts 61 | 62 | d7_log: 63 | lda #0 64 | sta PrintColor 65 | macro_putstr_inline " Page " 66 | inc PrintColor 67 | lda INPUT+1 68 | jsr _puthex 69 | dec PrintColor 70 | macro_putstr_inline " / " 71 | inc PrintColor 72 | inc PrintColor 73 | lda #HIGH(day7_input_end) 74 | jsr _puthex 75 | jmp wait_flush 76 | 77 | day7_solve: 78 | macro_memset_pb $6000, $00, $2000 79 | 80 | lda #LOW(day7_input) 81 | sta INPUT 82 | lda #HIGH(day7_input) 83 | sta INPUT+1 84 | .next_input: 85 | lda INPUT 86 | cmp #LOW(day7_input_end) 87 | bne .not_end 88 | jsr d7_log 89 | lda INPUT+1 90 | cmp #HIGH(day7_input_end) 91 | bne .not_end 92 | jmp d7_find_min 93 | .not_end: 94 | jsr read_next 95 | sta D7_Curr 96 | jsr read_next 97 | sta D7_Curr+1 98 | lda #LOW($6000) 99 | sta D7_CostIter 100 | lda #HIGH($6000) 101 | sta D7_CostIter+1 102 | ; CostIter => CostIndex 103 | .next_cost: 104 | lda D7_CostIter 105 | sta MathLhs 106 | lda D7_CostIter+1 107 | sta MathLhs+1 108 | macro_sub16_imm16 MathLhs, $6000 109 | ; MathLhs -= CostIter-$6000 110 | lsr MathLhs+1 111 | ror MathLhs 112 | lsr MathLhs+1 113 | ror MathLhs 114 | ; MathLhs /= 4 115 | macro_sub16 MathLhs, D7_Curr 116 | macro_abs16 MathLhs 117 | lda #0 118 | sta MathLhs+2 119 | sta MathLhs+3 120 | lda D7_SmartCrab 121 | beq .not_smart 122 | jsr smartify 123 | .not_smart: 124 | ldy #0 125 | lda [D7_CostIter],Y 126 | sta MathRhs 127 | iny 128 | lda [D7_CostIter],Y 129 | sta MathRhs+1 130 | iny 131 | lda [D7_CostIter],Y 132 | sta MathRhs+2 133 | iny 134 | lda [D7_CostIter],Y 135 | sta MathRhs+3 136 | macro_add32 MathLhs, MathRhs 137 | ldy #0 138 | lda MathLhs 139 | sta [D7_CostIter], Y 140 | iny 141 | lda MathLhs+1 142 | sta [D7_CostIter], Y 143 | iny 144 | lda MathLhs+2 145 | sta [D7_CostIter], Y 146 | iny 147 | lda MathLhs+3 148 | sta [D7_CostIter], Y 149 | macro_add16_imm8 D7_CostIter, 4 150 | lda D7_CostIter+1 151 | cmp #$80 152 | beq .no_more_cost 153 | jmp .next_cost 154 | .no_more_cost: 155 | jmp .next_input 156 | 157 | day7_solve_a: 158 | jmp day7_solve 159 | 160 | day7_solve_b: 161 | inc D7_SmartCrab 162 | jmp day7_solve 163 | 164 | -------------------------------------------------------------------------------- /day7_input.asm: -------------------------------------------------------------------------------- 1 | day7_input: 2 | IF 0 3 | dw 16,1,2,0,4,2,7,1,2,14 4 | ELSE 5 | dw 1101,1,29,67,1102,0,1,65,1008,65,35,66,1005,66,28,1 6 | dw 67,65,20,4,0,1001,65,1,65,1106,0,8,99,35,67,101 7 | dw 99,105,32,110,39,101,115,116,32,112,97,115,32,117,110,101 8 | dw 32,105,110,116,99,111,100,101,32,112,114,111,103,114,97,109 9 | dw 10,36,179,113,77,919,469,943,361,320,513,272,735,839,82,41 10 | dw 318,295,1758,280,1294,368,455,165,475,865,864,90,481,485,1517,554 11 | dw 32,104,1125,518,1280,165,423,209,188,1803,338,165,295,1082,715,343 12 | dw 15,316,71,310,282,239,779,314,759,1092,609,268,490,175,10,241 13 | dw 246,949,75,217,1,97,81,509,552,642,55,221,105,131,906,247 14 | dw 500,534,400,268,727,1395,47,570,318,38,370,2,1290,95,285,11 15 | dw 453,563,6,64,379,823,52,815,1678,86,543,378,732,188,106,68 16 | dw 173,400,23,295,548,484,74,574,656,1010,1607,1170,256,381,1452,400 17 | dw 136,68,1285,145,595,512,26,1745,737,757,193,361,1284,127,96,659 18 | dw 272,114,409,393,868,270,740,326,902,1862,524,799,632,465,714,1416 19 | dw 1,10,921,181,1302,7,430,294,241,694,29,402,71,263,585,193 20 | dw 194,808,175,1240,245,309,108,989,287,8,422,1760,80,120,5,551 21 | dw 596,15,455,134,970,106,1041,600,158,221,88,115,284,68,378,1023 22 | dw 815,251,238,287,280,406,1398,690,612,285,1167,235,10,915,13,1497 23 | dw 254,1317,1482,1119,1207,829,165,280,438,669,482,550,775,727,1760,473 24 | dw 550,992,33,215,681,1789,821,492,230,12,629,55,1218,342,292,35 25 | dw 503,739,594,243,24,678,101,800,138,1652,512,73,318,1611,9,47 26 | dw 1041,168,880,72,121,313,201,605,865,249,356,568,513,618,184,481 27 | dw 111,1602,660,206,529,745,492,207,537,493,457,28,633,59,214,653 28 | dw 1250,1001,133,140,1496,109,893,323,6,649,653,264,255,1549,1814,440 29 | dw 72,347,353,420,662,592,840,78,238,1165,485,1544,515,297,531,258 30 | dw 305,149,129,5,19,235,1658,222,217,1180,627,51,1056,186,1345,468 31 | dw 77,111,305,183,312,367,293,775,777,103,418,295,1066,108,1544,234 32 | dw 225,39,1233,626,163,643,371,191,1588,279,1560,754,1198,580,82,43 33 | dw 975,92,1118,29,87,1162,80,537,1216,1332,298,91,747,264,29,910 34 | dw 136,11,22,21,115,17,958,722,678,734,2,438,313,210,109,151 35 | dw 1072,1,1270,326,276,472,964,1349,1390,27,810,42,33,411,545,147 36 | dw 10,944,1023,704,652,912,13,324,91,34,539,174,776,41,378,320 37 | dw 61,169,454,10,9,223,126,1,684,721,475,482,132,278,1635,943 38 | dw 41,182,417,142,387,540,205,1409,392,420,1430,78,473,1160,347,890 39 | dw 716,62,205,258,676,500,60,290,566,942,363,104,19,490,731,885 40 | dw 837,345,776,193,1679,361,75,26,11,972,252,230,1243,1829,65,210 41 | dw 291,545,306,316,31,841,582,24,452,459,571,362,178,277,844,175 42 | dw 1010,339,55,360,413,1555,320,1050,28,1417,285,109,448,188,119,538 43 | dw 136,430,971,144,324,276,993,795,246,47,1258,638,1149,743,288,181 44 | dw 470,280,459,1392,2,570,147,143,32,70,904,554,84,1092,555,722 45 | dw 419,576,434,216,783,752,667,136,765,64,86,648,685,105,865,80 46 | dw 365,410,799,981,1546,1215,212,1406,716,1053,158,259,52,48,311,294 47 | dw 1186,716,484,343,101,13,712,767,168,39,108,245,64,728,236,870 48 | dw 976,328,65,252,322,148,506,1347,1478,417,853,362,356,3,739,323 49 | dw 1068,499,644,1432,50,836,136,140,1276,1307,212,748,767,1012,1237,32 50 | dw 304,243,26,239,69,1133,528,303,658,335,373,10,36,47,143,1476 51 | dw 476,991,668,1447,157,243,225,737,1733,43,772,814,1032,24,41,365 52 | dw 69,260,49,567,1113,67,5,122,520,11,349,11,519,127,383,481 53 | dw 605,1196,749,260,67,201,78,451,267,332,15,1855,554,144,94,20 54 | dw 13,761,61,25,237,3,196,695,1202,692,156,558,1410,240,526,68 55 | dw 223,743,5,1067,985,29,944,324,1040,69,1204,67,37,837,366,698 56 | dw 704,864,771,0,63,305,754,529,522,112,247,521,526,341,551,40 57 | dw 531,46,118,212,1024,305,440,238,339,581,201,840,41,811,115,236 58 | dw 1000,434,187,290,705,456,625,280,22,1203,861,35,380,101,923,462 59 | dw 570,479,860,450,40,676,959,391,396,194,52,862,217,725,14,273 60 | dw 63,475,43,496,1174,397,281,963,160,113,146,244,912,923,467,561 61 | dw 1180,354,802,188,214,2,100,1789,534,362,34,1148,998,231,460,28 62 | dw 117,471,412,651,513,305,986,121,175,447,566,76,1212,634,92,1523 63 | dw 671,802,36,81,791,503,1277,35,379,45,677,156,1,518,205,656 64 | dw 170,797,445,307,899,319,1104,806,842,272,1047,230,19,507,162,498 65 | dw 524,678,262,108,143,221,155,629,681,309,156,35,396,1440,796,302 66 | dw 6,857,1218,737,767,1465,8,236,550,20,334,371,282,381,167,211 67 | dw 398,937,185,282,389,464,343,160 68 | ENDIF 69 | day7_input_end: 70 | -------------------------------------------------------------------------------- /day8.asm: -------------------------------------------------------------------------------- 1 | INPUT .equ WORK 2 | D8_W .equ WORK+2 3 | D8_Num .equ WORK+3 4 | D8_it .equ WORK+4 5 | D8_M .equ WORK+5 6 | D8_IsB .equ WORK+6 7 | 8 | decoded_nums .equ $6010 9 | 10 | macro_decode .macro 11 | lda #9 12 | sta D8_it 13 | .read_more\@: 14 | ldx D8_it 15 | lda $6000, x 16 | sta D8_Num 17 | jsr \1 18 | ldx D8_it 19 | dex 20 | stx D8_it 21 | bpl .read_more\@ 22 | .endm 23 | 24 | 25 | macro_translat_mult .macro ; this... is so retarded. 26 | jsr translate_digit 27 | sta MathLhs 28 | lda #LOW(\1) 29 | sta MathRhs 30 | lda #HIGH(\1) 31 | sta MathRhs+1 32 | jsr math_mul32 33 | macro_add16 Result, MathOut 34 | .endm 35 | 36 | 37 | decode_easy: 38 | jsr bits_set 39 | cmp #2 40 | bne .not_1 41 | lda D8_Num 42 | sta decoded_nums+1 43 | rts 44 | .not_1: 45 | cmp #4 46 | bne .not_4 47 | lda D8_Num 48 | sta decoded_nums+4 49 | rts 50 | .not_4: 51 | cmp #3 52 | bne .not_7 53 | lda D8_Num 54 | sta decoded_nums+7 55 | rts 56 | .not_7: 57 | cmp #7 58 | bne .not_8 59 | lda D8_Num 60 | sta decoded_nums+8 61 | .not_8: 62 | rts 63 | 64 | decode_hard: 65 | jsr bits_set 66 | cmp #6 67 | bne .not_len6 68 | lda D8_Num 69 | and decoded_nums+4 70 | cmp decoded_nums+4 71 | bne .not_9 72 | lda D8_Num 73 | sta decoded_nums+9 74 | rts 75 | .not_9: 76 | lda D8_Num 77 | and decoded_nums+1 78 | cmp decoded_nums+1 79 | bne .is_6 80 | lda D8_Num 81 | sta decoded_nums+0 82 | rts 83 | .is_6: 84 | lda D8_Num 85 | sta decoded_nums+6 86 | rts 87 | .not_len6: 88 | cmp #5 89 | bne .exit 90 | lda D8_Num 91 | and decoded_nums+1 92 | cmp decoded_nums+1 93 | bne .exit 94 | lda D8_Num 95 | sta decoded_nums+3 96 | .exit: 97 | rts 98 | 99 | decode_two_five: 100 | jsr bits_set 101 | cmp #5 102 | bne .exit 103 | lda D8_Num 104 | and decoded_nums+1 105 | cmp decoded_nums+1 106 | beq .exit 107 | lda D8_Num 108 | and decoded_nums+6 109 | cmp D8_Num 110 | bne .is_2 111 | lda D8_Num 112 | sta decoded_nums+5 113 | rts 114 | .is_2: 115 | lda D8_Num 116 | sta decoded_nums+2 117 | .exit: 118 | rts 119 | 120 | bits_set: 121 | ldx #0 122 | sta D8_W 123 | lda #$80 124 | sta D8_M 125 | .next: 126 | and D8_W 127 | beq .not_set 128 | inx 129 | .not_set: 130 | lda D8_M 131 | lsr a 132 | sta D8_M 133 | bne .next 134 | txa 135 | rts 136 | 137 | chr_to_n: 138 | sta D8_W 139 | lda #'g' 140 | sec 141 | sbc D8_W 142 | sta D8_W 143 | lda #1 144 | ldx D8_W 145 | beq .done 146 | .more: 147 | asl a 148 | dex 149 | bne .more 150 | .done: 151 | ora D8_Num 152 | sta D8_Num 153 | rts 154 | 155 | translate_digit: 156 | jsr read_word 157 | ldx #0 158 | .gogo: 159 | cmp decoded_nums, x 160 | beq .done 161 | inx 162 | bne .gogo 163 | .done: 164 | txa 165 | rts 166 | 167 | read_word: 168 | lda #0 169 | sta D8_Num 170 | .next_chr: 171 | jsr read_next 172 | cmp #' ' 173 | beq .done 174 | cmp #0 175 | beq .done 176 | jsr chr_to_n 177 | jmp .next_chr 178 | .done: 179 | lda D8_Num 180 | rts 181 | 182 | count_if_1478: 183 | jsr read_word 184 | cmp decoded_nums+1 185 | beq .count 186 | cmp decoded_nums+4 187 | beq .count 188 | cmp decoded_nums+7 189 | beq .count 190 | cmp decoded_nums+8 191 | beq .count 192 | rts 193 | .count: 194 | macro_add16_imm8 Result, 1 195 | rts 196 | 197 | d8_do_b_stuff: 198 | macro_translat_mult 1000 199 | macro_translat_mult 100 200 | macro_translat_mult 10 201 | jsr translate_digit 202 | sta MathLhs 203 | macro_add16 Result, MathLhs 204 | rts 205 | 206 | day8_solve: 207 | lda #LOW(day8_input) 208 | sta INPUT 209 | lda #HIGH(day8_input) 210 | sta INPUT+1 211 | .next_line: 212 | lda INPUT 213 | cmp #LOW(day8_input_end) 214 | bne .do_next_line 215 | lda INPUT+1 216 | cmp #HIGH(day8_input_end) 217 | bne .do_next_line 218 | rts 219 | .do_next_line: 220 | lda #10 221 | sta D8_it 222 | .read_more: 223 | jsr read_word 224 | ldx D8_it 225 | dex 226 | stx D8_it 227 | sta $6000, x 228 | bne .read_more 229 | macro_decode decode_easy 230 | macro_decode decode_hard 231 | macro_decode decode_two_five 232 | ; Everything decoded now. Solve. 233 | lda D8_IsB 234 | beq .not_b 235 | jsr d8_do_b_stuff 236 | jmp .next_line 237 | .not_b: 238 | jsr count_if_1478 239 | jsr count_if_1478 240 | jsr count_if_1478 241 | jsr count_if_1478 242 | jmp .next_line 243 | 244 | day8_solve_a: 245 | jmp day8_solve 246 | 247 | day8_solve_b: 248 | inc D8_IsB 249 | jmp day8_solve -------------------------------------------------------------------------------- /day8_input.asm: -------------------------------------------------------------------------------- 1 | day8_input: 2 | db "be cfbegad cbdgef fgaecd cgeb fdcge agebfd fecdb fabcd edb fdgacbe cefdb cefbgd gcbe",0 3 | db "edbfga begcd cbg gc gcadebf fbgde acbgfd abcde gfcbed gfec fcgedb cgb dgebacf gc",0 4 | db "fgaebd cg bdaec gdafb agbcfd gdcbef bgcad gfac gcb cdgabef cg cg fdcagb cbg",0 5 | db "fbegcd cbd adcefb dageb afcb bc aefdc ecdab fgdeca fcdbega efabcd cedba gadfec cb",0 6 | db "aecbfdg fbg gf bafeg dbefa fcge gcbea fcaegb dgceab fcbdga gecf egdcabf bgf bfgea",0 7 | db "fgeab ca afcebg bdacfeg cfaedg gcfdb baec bfadeg bafgc acf gebdcfa ecba ca fadegcb",0 8 | db "dbcfg fgd bdegcaf fgec aegbdf ecdfab fbedc dacgb gdcebf gf cefg dcbef fcge gbcadfe",0 9 | db "bdfegc cbegaf gecbf dfcage bdacg ed bedf ced adcbefg gebcd ed bcgafe cdgba cbgef",0 10 | db "egadfb cdbfeg cegd fecab cgb gbdefca cg fgcdab egfdb bfceg gbdfcae bgc cg cgb",0 11 | db "gcafb gcf dcaebfg ecagb gf abcdeg gaef cafbge fdbac fegbdc fgae cfgab fg bagce",0 12 | day8_input_end: -------------------------------------------------------------------------------- /day9.asm: -------------------------------------------------------------------------------- 1 | BX .equ WORK 2 | BY .equ WORK+1 3 | SaveX .equ WORK+2 4 | SaveY .equ WORK+3 5 | CurrTile .equ WORK+4 6 | NumValley .equ WORK+5 7 | SumValley .equ WORK+6 ; and 7 8 | SizeBasin .equ WORK+8 9 | ItBasin .equ WORK+9 10 | PX .equ WORK+$a 11 | PY .equ WORK+$b 12 | TX .equ WORK+$c 13 | TY .equ WORK+$d 14 | BigBasins .equ Day9_SaveShit ; +1, +2 15 | 16 | oob: 17 | lda #9 18 | rts 19 | d9_readtile: 20 | cpx #100 21 | bcs oob ; solves negative numbers too (unsigned) 22 | cpy #100 23 | bcs oob ; --||-- 24 | stx SaveX 25 | sty MathLhs 26 | lda #100 ; Width 27 | sta MathRhs 28 | lda #0 29 | sta MathLhs+1 30 | sta MathRhs+1 31 | jsr math_mul32 32 | ; Y * 100 33 | lda MathOut 34 | sta MathRhs 35 | lda MathOut+1 36 | sta MathRhs+1 ; 100x100 is max 16-bit... 37 | lda SaveX 38 | sta MathLhs 39 | lda #0 40 | sta MathLhs+1 ; Save X 41 | jsr math_add16 ; out = x + y*100 42 | lda MathOut 43 | sta MathRhs 44 | lda MathOut+1 45 | sta MathRhs+1 46 | lda #LOW(day9_matrix) 47 | sta MathLhs 48 | lda #HIGH(day9_matrix) 49 | sta MathLhs+1 50 | jsr math_add16 51 | ; out = matrix + x + y*100 52 | ldy #0 53 | lda [MathOut], Y 54 | rts 55 | 56 | is_valley: 57 | ldx BX 58 | ldy BY 59 | jsr d9_readtile 60 | sta CurrTile 61 | ; 62 | ; -1,0 63 | ; 64 | ldx BX 65 | dex 66 | ldy BY 67 | jsr d9_readtile 68 | cmp CurrTile 69 | beq .too_low 70 | bmi .too_low 71 | ; 72 | ; 1,0 73 | ; 74 | ldx BX 75 | inx 76 | ldy BY 77 | jsr d9_readtile 78 | cmp CurrTile 79 | beq .too_low 80 | bmi .too_low 81 | ; 82 | ; 0,-1 83 | ; 84 | ldx BX 85 | ldy BY 86 | dey 87 | jsr d9_readtile 88 | cmp CurrTile 89 | beq .too_low 90 | bmi .too_low 91 | ; 92 | ; 0,1 93 | ; 94 | ldx BX 95 | ldy BY 96 | iny 97 | jsr d9_readtile 98 | cmp CurrTile 99 | beq .too_low 100 | bmi .too_low 101 | lda #1 102 | rts 103 | .too_low: 104 | lda #0 105 | rts 106 | 107 | add_basin_tile: 108 | stx SaveX 109 | sty SaveY 110 | ldx #0 111 | .check_next: 112 | cpx SizeBasin 113 | beq .at_end 114 | lda $6000,x 115 | cmp SaveX 116 | bne .not_equal 117 | lda $6001,x 118 | cmp SaveY 119 | bne .not_equal 120 | rts ; Already in list. 121 | .not_equal: 122 | inx 123 | inx 124 | jmp .check_next 125 | .at_end: 126 | lda SaveX 127 | sta $6000, x 128 | lda SaveY 129 | sta $6001, x 130 | inx 131 | inx 132 | stx SizeBasin 133 | rts 134 | 135 | set_tx_ty: 136 | ldx PX 137 | stx TX 138 | ldy PY 139 | sty TY 140 | rts 141 | 142 | calc_basin_inner: 143 | jsr set_tx_ty 144 | .scan_up: 145 | ldx TX 146 | ldy TY 147 | dey 148 | sty TY 149 | jsr d9_readtile 150 | cmp #9 151 | beq .scan_down_start 152 | ldx TX 153 | ldy TY 154 | jsr add_basin_tile 155 | jmp .scan_up 156 | .scan_down_start: 157 | jsr set_tx_ty 158 | .scan_down: 159 | ldx TX 160 | ldy TY 161 | iny 162 | sty TY 163 | jsr d9_readtile 164 | cmp #9 165 | beq .scan_left_start 166 | ldx TX 167 | ldy TY 168 | jsr add_basin_tile 169 | jmp .scan_down 170 | .scan_left_start: 171 | jsr set_tx_ty 172 | .scan_left: 173 | ldx TX 174 | dex 175 | stx TX 176 | ldy TY 177 | jsr d9_readtile 178 | cmp #9 179 | beq .scan_right_start 180 | ldx TX 181 | ldy TY 182 | jsr add_basin_tile 183 | jmp .scan_left 184 | .scan_right_start: 185 | jsr set_tx_ty 186 | .scan_right: 187 | ldx TX 188 | inx 189 | stx TX 190 | ldy TY 191 | jsr d9_readtile 192 | cmp #9 193 | beq .scan_done 194 | ldx TX 195 | ldy TY 196 | jsr add_basin_tile 197 | jmp .scan_right 198 | .scan_done: 199 | rts 200 | 201 | calc_basin: 202 | lda #0 203 | sta SizeBasin 204 | sta ItBasin 205 | ldx BX 206 | ldy BY 207 | jsr add_basin_tile 208 | ldx ItBasin 209 | .next_tile: 210 | lda $6000,x 211 | sta PX 212 | lda $6001,x 213 | sta PY 214 | jsr calc_basin_inner 215 | ldx ItBasin 216 | inx 217 | inx 218 | stx ItBasin 219 | cpx SizeBasin 220 | bne .next_tile 221 | ; Save it sortedly. 222 | lda SizeBasin 223 | lsr a 224 | cmp BigBasins 225 | bcc .not_max 226 | ldx BigBasins+1 227 | stx BigBasins+2 228 | ldx BigBasins 229 | stx BigBasins+1 230 | sta BigBasins 231 | rts 232 | .not_max: 233 | cmp BigBasins+1 234 | bcc .not_mid 235 | ldx BigBasins+1 236 | stx BigBasins+2 237 | sta BigBasins+1 238 | rts 239 | .not_mid: 240 | cmp BigBasins+2 241 | bcc .not_min 242 | sta BigBasins+2 243 | .not_min: 244 | rts 245 | 246 | process_valley: 247 | jsr is_valley 248 | beq .not_a_valley 249 | inc NumValley 250 | ldx CurrTile 251 | inx 252 | stx MathLhs 253 | lda #0 254 | sta MathLhs+1 255 | tmm16 MathRhs, SumValley 256 | jsr math_add16 257 | tmm16 SumValley, MathOut 258 | jmp calc_basin 259 | .not_a_valley: 260 | rts 261 | 262 | day9_solve_a: 263 | lda #0 264 | sta BX 265 | sta BY 266 | .next_tile: 267 | jsr process_valley 268 | ldx BX 269 | inx 270 | stx BX 271 | cpx #100 272 | bne .next_tile 273 | lda #0 274 | sta PrintColor 275 | macro_putstr_inline " Finished row " 276 | inc PrintColor 277 | lda BY 278 | jsr _puthex 279 | jsr wait_flush 280 | ldx #0 281 | stx BX 282 | ldx BY 283 | inx 284 | stx BY 285 | cpx #100 286 | bne .next_tile 287 | tmm16 Result, SumValley 288 | rts 289 | 290 | day9_solve_b: 291 | lda BigBasins 292 | sta MathLhs 293 | lda BigBasins+1 294 | sta MathRhs 295 | jsr math_mul32 296 | tmm16 MathLhs, MathOut 297 | lda BigBasins+2 298 | sta MathRhs 299 | jsr math_mul32 300 | tmm32 Result, MathOut 301 | rts 302 | 303 | -------------------------------------------------------------------------------- /intro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pellsson/aoc2021/e71a765ea4cd3293ac239f629dc87f45888fe470/intro.png -------------------------------------------------------------------------------- /macros.asm: -------------------------------------------------------------------------------- 1 | macro_putstr_inline .macro 2 | jmp .p\@ 3 | .str\@: 4 | db \1, 0 5 | .p\@: 6 | lda #LOW(.str\@) 7 | sta TMP 8 | lda #HIGH(.str\@) 9 | sta TMP+1 10 | jsr putstr 11 | .endm 12 | 13 | macro_putstr .macro 14 | lda #LOW(\1) 15 | sta TMP 16 | lda #HIGH(\1) 17 | sta TMP+1 18 | jsr putstr 19 | .endm 20 | 21 | macro_add16_imm8 .macro 22 | clc 23 | lda \1 24 | adc #\2 25 | sta \1 26 | lda \1+1 27 | adc #0 28 | sta \1+1 29 | .endm 30 | 31 | macro_add16_imm16 .macro 32 | clc 33 | lda \1 34 | adc #LOW(\2) 35 | sta \1 36 | lda \1+1 37 | adc #HIGH(\2) 38 | sta \1+1 39 | .endm 40 | 41 | macro_sub16_imm8 .macro 42 | sec 43 | lda \1 44 | sbc #\2 45 | sta \1 46 | lda \1+1 47 | sbc #0 48 | sta \1+1 49 | .endm 50 | 51 | macro_sub16_imm16 .macro 52 | sec 53 | lda \1 54 | sbc #LOW(\2) 55 | sta \1 56 | lda \1+1 57 | sbc #HIGH(\2) 58 | sta \1+1 59 | .endm 60 | 61 | macro_abs16 .macro 62 | lda \1+1 63 | bpl .done\@ 64 | lda \1 65 | eor #$FF 66 | sta \1 67 | lda \1+1 68 | eor #$ff 69 | sta \1+1 70 | inc \1 71 | bne .done\@ 72 | inc \1+1 73 | .done\@: 74 | .endm 75 | 76 | macro_sub16_out .macro 77 | sec 78 | lda \2 79 | sbc \3 80 | sta \1 81 | lda \2+1 82 | sbc \3+1 83 | sta \1+1 84 | .endm 85 | 86 | macro_sub16 .macro 87 | macro_sub16_out \1, \1, \2 88 | .endm 89 | 90 | macro_sub32_out .macro 91 | macro_sub16_out \1, \2, \3 92 | lda \2+2 93 | sbc \3+2 94 | sta \1+2 95 | lda \2+3 96 | sbc \3+3 97 | sta \1+3 98 | .endm 99 | 100 | macro_sub32 .macro 101 | macro_sub32_out \1, \1, \2 102 | .endm 103 | 104 | macro_sub64_out .macro 105 | macro_sub32_out \1, \2, \3 106 | lda \2+4 107 | sbc \3+4 108 | sta \1+4 109 | lda \2+5 110 | sbc \3+5 111 | sta \1+5 112 | lda \2+6 113 | sbc \3+6 114 | sta \1+6 115 | lda \2+7 116 | sbc \3+7 117 | sta \1+7 118 | .endm 119 | 120 | macro_sub64 .macro 121 | macro_sub64_out \1, \1, \2 122 | .endm 123 | 124 | macro_add16_out .macro 125 | clc 126 | lda \2 127 | adc \3 128 | sta \1 129 | lda \2+1 130 | adc \3+1 131 | sta \1+1 132 | .endm 133 | 134 | macro_add16 .macro 135 | macro_add16_out \1, \1, \2 136 | .endm 137 | 138 | macro_add32_out .macro 139 | macro_add16_out \1, \2, \3 140 | lda \2+2 141 | adc \3+2 142 | sta \1+2 143 | lda \2+3 144 | adc \3+3 145 | sta \1+3 146 | .endm 147 | 148 | macro_add32 .macro 149 | macro_add32_out \1, \1, \2 150 | .endm 151 | 152 | macro_add64_out .macro 153 | macro_add32_out \1, \2, \3 154 | lda \2+4 155 | adc \3+4 156 | sta \1+4 157 | lda \2+5 158 | adc \3+5 159 | sta \1+5 160 | lda \2+6 161 | adc \3+6 162 | sta \1+6 163 | lda \2+7 164 | adc \3+7 165 | sta \1+7 166 | .endm 167 | 168 | macro_add64 .macro 169 | macro_add64_out \1, \1, \2 170 | .endm 171 | 172 | macro_inc32 .macro 173 | inc \1 174 | bne .done 175 | inc \1+1 176 | bne .done 177 | inc \1+2 178 | bne .done 179 | inc \1+3 180 | .done: 181 | .endm 182 | 183 | macro_mul16 .macro 184 | lda \1 185 | sta MathLhs 186 | lda \1+1 187 | sta MathLhs+1 188 | lda \2 189 | sta MathRhs 190 | lda \2+1 191 | sta MathRhs+1 192 | jsr math_mul32 193 | .endm 194 | 195 | macro_mul16_imm16 .macro 196 | lda #LOW(\2) 197 | sta MathRhs 198 | lda #HIGH(\2) 199 | sta MathRhs+1 200 | lda \1 201 | sta MathLhs 202 | lda \1+1 203 | sta MathLhs+1 204 | jsr math_mul32 205 | .endm 206 | 207 | macro_max_u16 .macro 208 | lda \2+1 209 | cmp \3+1 210 | beq .check_low\@ 211 | bcs .lhs_bigger\@ 212 | .rhs_bigger\@: 213 | lda \3 214 | sta \1 215 | lda \3+1 216 | sta \1+1 217 | jmp .end\@ 218 | .check_low\@: 219 | lda \2 220 | cmp \3 221 | bcc .rhs_bigger\@ 222 | .lhs_bigger\@: 223 | lda \2 224 | sta \1 225 | lda \2+1 226 | sta \1+1 227 | .end\@: 228 | .endm 229 | 230 | macro_min_u16 .macro 231 | lda \2+1 232 | cmp \3+1 233 | beq .check_low\@ 234 | bcs .lhs_bigger\@ 235 | .rhs_bigger\@: 236 | lda \2 237 | sta \1 238 | lda \2+1 239 | sta \1+1 240 | jmp .end\@ 241 | .check_low\@: 242 | lda \2 243 | cmp \3 244 | bcc .rhs_bigger\@ 245 | .lhs_bigger\@: 246 | lda \3 247 | sta \1 248 | lda \3+1 249 | sta \1+1 250 | .end\@: 251 | .endm 252 | 253 | 254 | 255 | tmm16 .macro 256 | lda \2 257 | sta \1 258 | lda \2+1 259 | sta \1+1 260 | .endm 261 | 262 | tmm32 .macro 263 | tmm16 \1, \2 264 | tmm16 \1+2, \2+2 265 | .endm 266 | 267 | tmm64 .macro 268 | tmm32 \1, \2 269 | tmm32 \1+4, \2+4 270 | .endm 271 | 272 | tmm40 .macro 273 | tmm32 \1, \2 274 | lda \2+4 275 | sta \1+4 276 | .endm 277 | 278 | macro_memcpy .macro 279 | lda #LOW(\1) 280 | sta Src 281 | lda #HIGH(\1) 282 | sta Src+1 283 | lda #LOW(\2) 284 | sta SrcEnd 285 | lda #HIGH(\2) 286 | sta SrcEnd+1 287 | lda #LOW(\3) 288 | sta Dst 289 | lda #HIGH(\3) 290 | sta Dst+1 291 | jsr _memcpy 292 | .endm 293 | 294 | macro_memset_pb .macro 295 | lda #LOW(\1) 296 | sta Dst 297 | lda #HIGH(\1) 298 | sta Dst+1 299 | lda #\2 300 | ldx #HIGH((\3+$FF) & $FF00) 301 | ldy #0 302 | .next\@: 303 | sta [Dst], Y 304 | iny 305 | bne .next\@ 306 | macro_add16_imm16 Dst, $100 307 | lda #\2 308 | dex 309 | bne .next\@ 310 | .endm 311 | 312 | macro_is_less_u16 .macro 313 | lda \1+1 314 | cmp \2+1 315 | bcc \3 ; Lower! 316 | bne .higher\@ 317 | lda \1 318 | cmp \2 319 | bcc \3 ; Lower! 320 | ; Higher or equal 321 | .higher\@: 322 | .endm 323 | 324 | macro_is_less_u32 .macro 325 | lda \1+3 326 | cmp \2+3 327 | bcc \3 ; Lower! 328 | bne .higher_x\@ 329 | lda \1+2 330 | cmp \2+2 331 | bcc \3 ; Lower! 332 | macro_is_less_u16 \1, \2, \3 333 | .higher_x\@ 334 | .endm 335 | 336 | macro_is_less_u40 .macro 337 | lda \1+4 338 | cmp \2+4 339 | bcc \3 340 | bne .higher_xx\@ 341 | macro_is_less_u32 \1, \2, \3 342 | .higher_xx\@: 343 | .endm 344 | -------------------------------------------------------------------------------- /math.asm: -------------------------------------------------------------------------------- 1 | math_sub16: 2 | sec 3 | lda MathLhs 4 | sbc MathRhs 5 | sta MathOut 6 | lda MathLhs+1 7 | sbc MathRhs+1 8 | sta MathOut+1 9 | rts 10 | 11 | math_add16: 12 | clc 13 | lda MathLhs 14 | adc MathRhs 15 | sta MathOut 16 | lda MathLhs+1 17 | adc MathRhs+1 18 | sta MathOut+1 19 | rts 20 | 21 | math_sub32: 22 | jsr math_sub16 23 | lda MathLhs+2 24 | sbc MathRhs+2 25 | sta MathOut+2 26 | lda MathLhs+3 27 | sbc MathRhs+3 28 | sta MathOut+3 29 | rts 30 | 31 | math_add32: 32 | jsr math_add16 33 | lda MathLhs+2 34 | adc MathRhs+2 35 | sta MathOut+2 36 | lda MathLhs+3 37 | adc MathRhs+3 38 | sta MathOut+3 39 | rts 40 | 41 | ; http://6502.org/source/integers/32muldiv.htm 42 | math_mul32: 43 | lda #$00 44 | sta MathOut+4 ; Clear upper half of 45 | sta MathOut+5 ; MathOutuct 46 | sta MathOut+6 47 | sta MathOut+7 48 | ldx #$20 ; Set binary count to 32 49 | shift_r: 50 | lsr MathRhs+3 ; Shift multiplyer right 51 | ror MathRhs+2 52 | ror MathRhs+1 53 | ror MathRhs 54 | bcc rotate_r ; Go rotate right if c = 0 55 | lda MathOut+4 ; Get upper half of MathOutuct 56 | clc ; and add multiplicand to it 57 | adc MathLhs 58 | sta MathOut+4 59 | lda MathOut+5 60 | adc MathLhs+1 61 | sta MathOut+5 62 | lda MathOut+6 63 | adc MathLhs+2 64 | sta MathOut+6 65 | lda MathOut+7 66 | adc MathLhs+3 67 | rotate_r: 68 | ror a ; Rotate partial MathOutuct 69 | sta MathOut+7 ; right 70 | ror MathOut+6 71 | ror MathOut+5 72 | ror MathOut+4 73 | ror MathOut+3 74 | ror MathOut+2 75 | ror MathOut+1 76 | ror MathOut 77 | dex ; Decrement bit count and 78 | bne shift_r ; loop until 32 bits are 79 | rts 80 | 81 | math_max64: 82 | lda MathLhs+7 83 | cmp MathRhs+7 84 | beq .c6 85 | jmp math_mov_max 86 | .c6: 87 | lda MathLhs+6 88 | cmp MathRhs+6 89 | beq .c5 90 | jmp math_mov_max 91 | .c5: 92 | lda MathLhs+5 93 | cmp MathRhs+5 94 | beq .c4 95 | jmp math_mov_max 96 | .c4: 97 | lda MathLhs+4 98 | cmp MathRhs+4 99 | beq .c3 100 | jmp math_mov_max 101 | .c3: 102 | lda MathLhs+3 103 | cmp MathRhs+3 104 | beq .c2 105 | jmp math_mov_max 106 | .c2: 107 | lda MathLhs+2 108 | cmp MathRhs+2 109 | beq .c1 110 | jmp math_mov_max 111 | .c1: 112 | lda MathLhs+1 113 | cmp MathRhs+1 114 | beq .c0 115 | jmp math_mov_max 116 | .c0: 117 | lda MathLhs 118 | cmp MathRhs 119 | math_mov_max: 120 | bcc math_r_to_out 121 | math_l_to_out: 122 | tmm64 MathOut, MathLhs 123 | rts 124 | 125 | math_mov_min: 126 | bcc math_l_to_out 127 | math_r_to_out: 128 | tmm64 MathOut, MathRhs 129 | rts 130 | 131 | math_min64: 132 | lda MathLhs+7 133 | cmp MathRhs+7 134 | beq .c6 135 | jmp math_mov_min 136 | .c6: 137 | lda MathLhs+6 138 | cmp MathRhs+6 139 | beq .c5 140 | jmp math_mov_min 141 | .c5: 142 | lda MathLhs+5 143 | cmp MathRhs+5 144 | beq .c4 145 | jmp math_mov_min 146 | .c4: 147 | lda MathLhs+4 148 | cmp MathRhs+4 149 | beq .c3 150 | jmp math_mov_min 151 | .c3: 152 | lda MathLhs+3 153 | cmp MathRhs+3 154 | beq .c2 155 | jmp math_mov_min 156 | .c2: 157 | lda MathLhs+2 158 | cmp MathRhs+2 159 | beq .c1 160 | jmp math_mov_min 161 | .c1: 162 | lda MathLhs+1 163 | cmp MathRhs+1 164 | beq .c0 165 | jmp math_mov_min 166 | .c0: 167 | lda MathLhs 168 | cmp MathRhs 169 | jmp math_mov_min -------------------------------------------------------------------------------- /musicbank-8000.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pellsson/aoc2021/e71a765ea4cd3293ac239f629dc87f45888fe470/musicbank-8000.bin -------------------------------------------------------------------------------- /nesasm-vs.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pellsson/aoc2021/e71a765ea4cd3293ac239f629dc87f45888fe470/nesasm-vs.exe -------------------------------------------------------------------------------- /nesasmsrc/assemble.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "defs.h" 6 | #include "externs.h" 7 | #include "protos.h" 8 | 9 | int in_if; /* set when we are in an .if statement */ 10 | int if_expr; /* set when parsing an .if expression */ 11 | int if_level; /* level of nested .if's */ 12 | int if_state[256]; /* status when entering the .if */ 13 | int if_flag[256]; /* .if/.else status */ 14 | int skip_lines; /* set when lines must be skipped */ 15 | int continued_line; /* set when a line is the continuation of another line */ 16 | 17 | 18 | /* ---- 19 | * assemble() 20 | * ---- 21 | * translate source line to machine language 22 | */ 23 | void 24 | assemble(void) 25 | { 26 | struct t_line *ptr; 27 | char *buf; 28 | char c; 29 | int flag; 30 | int ip, i, j; /* prlnbuf pointer */ 31 | 32 | /* init variables */ 33 | lablptr = NULL; 34 | continued_line = 0; 35 | data_loccnt = -1; 36 | data_size = 3; 37 | data_level = 1; 38 | 39 | /* macro definition */ 40 | if (in_macro) { 41 | i = SFIELD; 42 | if (colsym(&i)) 43 | if (prlnbuf[i] == ':') 44 | i++; 45 | while (isspace(prlnbuf[i])) 46 | i++; 47 | if (pass == LAST_PASS) 48 | println(); 49 | if (oplook(&i) >= 0) { 50 | if (opflg == PSEUDO) { 51 | if (opval == P_MACRO) { 52 | error("Can not nest macro definitions!"); 53 | return; 54 | } 55 | if (opval == P_ENDM) { 56 | if (!check_eol(&i)) 57 | return; 58 | in_macro = 0; 59 | return; 60 | } 61 | } 62 | } 63 | if (pass == FIRST_PASS) { 64 | ptr = (void *)malloc(sizeof(struct t_line)); 65 | buf = (void *)malloc(strlen(&prlnbuf[SFIELD]) + 1); 66 | if ((ptr == NULL) || (buf == NULL)) { 67 | error("Out of memory!"); 68 | return; 69 | } 70 | strcpy(buf, &prlnbuf[SFIELD]); 71 | ptr->next = NULL; 72 | ptr->data = buf; 73 | if (mlptr) 74 | mlptr->next = ptr; 75 | else 76 | mptr->line = ptr; 77 | mlptr = ptr; 78 | } 79 | return; 80 | } 81 | 82 | /* IF/ELSE section; 83 | * check for a '.else' or '.endif' 84 | * to toggle state 85 | */ 86 | if (in_if) { 87 | i = SFIELD; 88 | while (isspace(prlnbuf[i])) 89 | i++; 90 | if (oplook(&i) >= 0) { 91 | if (opflg == PSEUDO) { 92 | switch (opval) { 93 | case P_IF: // .if 94 | case P_IFDEF: // .ifdef 95 | case P_IFNDEF: // .ifndef 96 | if (skip_lines) { 97 | if_level++; 98 | if_state[if_level] = 0; 99 | } 100 | break; 101 | 102 | case P_ELSE: // .else 103 | if (!check_eol(&i)) 104 | return; 105 | if (if_state[if_level]) { 106 | skip_lines = !if_flag[if_level]; 107 | if (pass == LAST_PASS) 108 | println(); 109 | } 110 | return; 111 | 112 | case P_ENDIF: // .endif 113 | if (!check_eol(&i)) 114 | return; 115 | if (if_state[if_level] && (pass == LAST_PASS)) 116 | println(); 117 | skip_lines = !if_state[if_level]; 118 | if_level--; 119 | if (if_level == 0) 120 | in_if = 0; 121 | return; 122 | } 123 | } 124 | } 125 | } 126 | 127 | if (skip_lines) 128 | return; 129 | 130 | /* comment line */ 131 | c = prlnbuf[SFIELD]; 132 | if (c == ';' || c == '*' || c == '\0') { 133 | // if (c == '\0') 134 | lastlabl = NULL; 135 | if (pass == LAST_PASS) 136 | println(); 137 | return; 138 | } 139 | 140 | /* search for a label */ 141 | i = SFIELD; 142 | j = 0; 143 | while (isspace(prlnbuf[i])) 144 | i++; 145 | for (;;) { 146 | c = prlnbuf[i + j]; 147 | if (isdigit(c) && (j == 0)) 148 | break; 149 | if (!isalnum(c) && (c != '_') && (c != '.')) 150 | break; 151 | j++; 152 | } 153 | if ((j == 0) || ((i != SFIELD) && (c != ':'))) 154 | i = SFIELD; 155 | else { 156 | if (colsym(&i) != 0) 157 | if ((lablptr = stlook(1)) == NULL) 158 | return; 159 | if ((lablptr) && (prlnbuf[i] == ':')) 160 | i++; 161 | } 162 | 163 | /* skip spaces */ 164 | while (isspace(prlnbuf[i])) 165 | i++; 166 | 167 | /* is it a macro? */ 168 | ip = i; 169 | mptr = macro_look(&ip); 170 | if (mptr) { 171 | /* define label */ 172 | labldef(loccnt, 1); 173 | 174 | /* output location counter */ 175 | if (pass == LAST_PASS) { 176 | if (!asm_opt[OPT_MACRO]) 177 | loadlc((page << XXX_BANK_SHIFT) + loccnt, 0); 178 | } 179 | 180 | /* get macro args */ 181 | if (!macro_getargs(ip)) 182 | return; 183 | 184 | /* output line */ 185 | if (pass == LAST_PASS) 186 | println(); 187 | 188 | /* ok */ 189 | mcntmax++; 190 | mcounter = mcntmax; 191 | expand_macro = 1; 192 | mlptr = mptr->line; 193 | return; 194 | } 195 | 196 | /* an instruction then */ 197 | ip = i; 198 | flag = oplook(&ip); 199 | if (flag < 0) { 200 | labldef(loccnt, 1); 201 | if ((flag == -1)) 202 | error("Unknown instruction!"); 203 | if ((flag == -2) && (pass == LAST_PASS)) { 204 | if (lablptr) 205 | loadlc(loccnt, 0); 206 | println(); 207 | } 208 | lastlabl = NULL; 209 | return; 210 | } 211 | 212 | /* generate code */ 213 | if (opflg == PSEUDO) 214 | do_pseudo(&ip); 215 | else if (labldef(loccnt, 1) == -1) 216 | return; 217 | else { 218 | /* output infos */ 219 | data_loccnt = loccnt; 220 | 221 | /* check if we are in the CODE section */ 222 | if (section != S_CODE) 223 | fatal_error("Instructions not allowed in this section!"); 224 | 225 | /* generate code */ 226 | opproc(&ip); 227 | 228 | /* reset last label pointer */ 229 | lastlabl = NULL; 230 | } 231 | } 232 | 233 | 234 | /* ---- 235 | * oplook() 236 | * ---- 237 | * operation code table lookup 238 | * return symbol length if found 239 | * return -1 on syntax error 240 | * return -2 if no symbol 241 | */ 242 | 243 | int 244 | oplook(int *idx) 245 | { 246 | struct t_opcode *ptr; 247 | char name[16]; 248 | char c; 249 | int flag; 250 | int hash; 251 | int i; 252 | 253 | /* get instruction name */ 254 | i = 0; 255 | opext = 0; 256 | flag = 0; 257 | hash = 0; 258 | 259 | for (;;) { 260 | c = toupper(prlnbuf[*idx]); 261 | if (c == ' ' || c == '\t' || c == '\0' || c == ';') 262 | break; 263 | if (!isalnum(c) && c != '.' && c != '*' && c != '=') 264 | return (-1); 265 | if (i == 15) 266 | return (-1); 267 | 268 | /* handle instruction extension */ 269 | if (c == '.' && i) { 270 | if (flag) 271 | return (-1); 272 | flag = 1; 273 | (*idx)++; 274 | continue; 275 | } 276 | if (flag) { 277 | if (opext) 278 | return (-1); 279 | opext = c; 280 | (*idx)++; 281 | continue; 282 | } 283 | 284 | /* store char */ 285 | name[i++] = c; 286 | hash += c; 287 | hash = (hash << 3) + (hash >> 5) + c; 288 | (*idx)++; 289 | 290 | /* break if '=' directive */ 291 | if (c == '=') 292 | break; 293 | } 294 | 295 | /* check extension */ 296 | if (flag) { 297 | if ((opext != 'L') && (opext != 'H')) 298 | return (-1); 299 | } 300 | 301 | /* end name string */ 302 | name[i] = '\0'; 303 | 304 | /* return if no instruction */ 305 | if (i == 0) 306 | return (-2); 307 | 308 | /* search the instruction in the hash table */ 309 | ptr = inst_tbl[hash & 0xFF]; 310 | 311 | while (ptr) { 312 | if (!strcmp(name, ptr->name)) { 313 | opproc = ptr->proc; 314 | opflg = ptr->flag; 315 | opval = ptr->value; 316 | optype = ptr->type_idx; 317 | 318 | if (opext) { 319 | /* no extension for pseudos */ 320 | if (opflg == PSEUDO) 321 | return (-1); 322 | /* extension valid only for these addressing modes */ 323 | if (!(opflg & (IMM|ZP|ZP_X|ZP_IND_Y|ABS|ABS_X|ABS_Y))) 324 | return (-1); 325 | } 326 | return (i); 327 | } 328 | ptr = ptr->next; 329 | } 330 | 331 | /* didn't find this instruction */ 332 | return (-1); 333 | } 334 | 335 | 336 | /* ---- 337 | * addinst() 338 | * ---- 339 | * add a list of instructions to the instruction 340 | * hash table 341 | */ 342 | 343 | void 344 | addinst(struct t_opcode *optbl) 345 | { 346 | int hash; 347 | int len; 348 | int i; 349 | char *ptr; 350 | char c; 351 | 352 | if (optbl == NULL) 353 | return; 354 | 355 | /* parse list */ 356 | while (optbl->name) { 357 | /* calculate instruction hash value */ 358 | hash = 0; 359 | len = strlen(optbl->name); 360 | ptr = optbl->name; 361 | 362 | for (i = 0; i < len; i++) { 363 | c = *ptr++; 364 | hash += c; 365 | hash = (hash << 3) + (hash >> 5) + c; 366 | } 367 | 368 | hash &= 0xFF; 369 | 370 | /* insert the instruction in the hash table */ 371 | optbl->next = inst_tbl[hash]; 372 | inst_tbl[hash] = optbl; 373 | 374 | /* next instruction */ 375 | optbl++; 376 | } 377 | } 378 | 379 | 380 | /* ---- 381 | * check_eol() 382 | * ---- 383 | * check the end of line for garbage 384 | */ 385 | 386 | int 387 | check_eol(int *ip) 388 | { 389 | while (isspace(prlnbuf[*ip])) 390 | (*ip)++; 391 | if (prlnbuf[*ip] == ';' || prlnbuf[*ip] == '\0') 392 | return (1); 393 | else { 394 | error("Syntax error!"); 395 | return (0); 396 | } 397 | } 398 | 399 | /* .if pseudo */ 400 | 401 | void 402 | do_if(int *ip) 403 | { 404 | labldef(loccnt, 1); 405 | 406 | /* get expression */ 407 | if_expr = 1; 408 | if (!evaluate(ip, ';')) { 409 | if_expr = 0; 410 | return; 411 | } 412 | if_expr = 0; 413 | 414 | /* check for '.if' stack overflow */ 415 | if (if_level == 255) { 416 | fatal_error("Too many nested IF/ENDIF!"); 417 | return; 418 | } 419 | in_if = 1; 420 | if_level++; 421 | if_state[if_level] = !skip_lines; 422 | if (!skip_lines) 423 | skip_lines = if_flag[if_level] = value ? 0 : 1; 424 | 425 | if (pass == LAST_PASS) { 426 | loadlc(value, 1); 427 | println(); 428 | } 429 | } 430 | 431 | /* .else pseudo */ 432 | 433 | void 434 | do_else(int *ip) 435 | { 436 | if (!in_if) 437 | fatal_error("Unexpected ELSE!"); 438 | } 439 | 440 | /* .endif pseudo */ 441 | 442 | void 443 | do_endif(int *ip) 444 | { 445 | if (!in_if) 446 | fatal_error("Unexpected ENDIF!"); 447 | } 448 | 449 | /* .ifdef/.ifndef pseudo */ 450 | 451 | void 452 | do_ifdef(int *ip) 453 | { 454 | labldef(loccnt, 1); 455 | 456 | /* skip spaces */ 457 | while (isspace(prlnbuf[*ip])) 458 | (*ip)++; 459 | 460 | /* get symbol */ 461 | if (!colsym(ip)) { 462 | error("Syntax error!"); 463 | return; 464 | } 465 | if (!check_eol(ip)) 466 | return; 467 | lablptr = stlook(0); 468 | 469 | /* check for '.if' stack overflow */ 470 | if (if_level == 255) { 471 | fatal_error("Too many nested IF/ENDIF!"); 472 | return; 473 | } 474 | in_if = 1; 475 | if_level++; 476 | if_state[if_level] = !skip_lines; 477 | if (!skip_lines) { 478 | if (optype) { 479 | /* .ifdef */ 480 | skip_lines = if_flag[if_level] = (lablptr == NULL) ? 1 : 0; 481 | } 482 | else { 483 | /* .ifndef */ 484 | skip_lines = if_flag[if_level] = (lablptr == NULL) ? 0 : 1; 485 | } 486 | } 487 | 488 | if (pass == LAST_PASS) { 489 | loadlc(!skip_lines, 1); 490 | println(); 491 | } 492 | } 493 | 494 | -------------------------------------------------------------------------------- /nesasmsrc/crc.c: -------------------------------------------------------------------------------- 1 | 2 | /* locals */ 3 | static unsigned int crc_table[256]; 4 | 5 | 6 | /* ---- 7 | * crc_init() 8 | * ---- 9 | */ 10 | 11 | void 12 | crc_init(void) 13 | { 14 | int i; 15 | unsigned int t, *p, *q; 16 | unsigned int poly = 0x864CFB; 17 | 18 | p = q = crc_table; 19 | *q++ = 0; 20 | *q++ = poly; 21 | 22 | for (i = 1; i < 128; i++) { 23 | t = *(++p); 24 | if (t & 0x800000) { 25 | t <<= 1; 26 | *q++ = t ^ poly; 27 | *q++ = t; 28 | } 29 | else { 30 | t <<= 1; 31 | *q++ = t; 32 | *q++ = t ^ poly; 33 | } 34 | } 35 | } 36 | 37 | 38 | /* ---- 39 | * crc_calc() 40 | * ---- 41 | * 24-bit crc 42 | */ 43 | 44 | unsigned int 45 | crc_calc(unsigned char *data, int len) 46 | { 47 | unsigned int crc = 0; 48 | int i; 49 | 50 | for (i = 0; i < len; i++) 51 | crc = (crc << 8) ^ crc_table[(unsigned char)(crc >> 16) ^ *data++]; 52 | 53 | /* ok */ 54 | return (crc & 0xFFFFFF); 55 | } 56 | 57 | -------------------------------------------------------------------------------- /nesasmsrc/defs.h: -------------------------------------------------------------------------------- 1 | #define XXX_BANK_SIZE 0x4000 2 | #define XXX_BANK_MASK (XXX_BANK_SIZE-1) 3 | #define XXX_BANK_SHIFT 14 4 | 5 | /* path separator */ 6 | #if defined(DJGPP) || defined(MSDOS) || defined(WIN32) 7 | #define PATH_SEPARATOR '\\' 8 | #define PATH_SEPARATOR_STRING "\\" 9 | #define strcasecmp _stricmp 10 | #define strncasecmp _strnicmp 11 | #else 12 | #define PATH_SEPARATOR '/' 13 | #define PATH_SEPARATOR_STRING "/" 14 | #endif 15 | 16 | /* machine */ 17 | #define MACHINE_PCE 0 18 | #define MACHINE_NES 1 19 | 20 | /* reserved bank index */ 21 | #define RESERVED_BANK 0xF0 22 | #define PROC_BANK 0xF1 23 | #define GROUP_BANK 0xF2 24 | 25 | /* tile format for encoder */ 26 | #define CHUNKY_TILE 1 27 | #define PACKED_TILE 2 28 | 29 | /* line buffer length */ 30 | #define LAST_CH_POS 1580 31 | #define SFIELD 26 32 | #define SBOLSZ 32 33 | 34 | /* macro argument types */ 35 | #define NO_ARG 0 36 | #define ARG_REG 1 37 | #define ARG_IMM 2 38 | #define ARG_ABS 3 39 | #define ARG_INDIRECT 4 40 | #define ARG_STRING 5 41 | #define ARG_LABEL 6 42 | 43 | /* section types */ 44 | #define S_ZP 0 45 | #define S_BSS 1 46 | #define S_CODE 2 47 | #define S_DATA 3 48 | 49 | /* assembler options */ 50 | #define OPT_LIST 0 51 | #define OPT_MACRO 1 52 | #define OPT_WARNING 2 53 | #define OPT_OPTIMIZE 3 54 | 55 | /* assembler directives */ 56 | #define P_DB 0 // .db 57 | #define P_DW 1 // .dw 58 | #define P_DS 2 // .ds 59 | #define P_EQU 3 // .equ 60 | #define P_ORG 4 // .org 61 | #define P_PAGE 5 // .page 62 | #define P_BANK 6 // .bank 63 | #define P_INCBIN 7 // .incbin 64 | #define P_INCLUDE 8 // .include 65 | #define P_INCCHR 9 // .incchr 66 | #define P_INCSPR 10 // .incspr 67 | #define P_INCPAL 11 // .incpal 68 | #define P_INCBAT 12 // .incbat 69 | #define P_MACRO 13 // .macro 70 | #define P_ENDM 14 // .endm 71 | #define P_LIST 15 // .list 72 | #define P_MLIST 16 // .mlist 73 | #define P_NOLIST 17 // .nolist 74 | #define P_NOMLIST 18 // .nomlist 75 | #define P_RSSET 19 // .rsset 76 | #define P_RS 20 // .rs 77 | #define P_IF 21 // .if 78 | #define P_ELSE 22 // .else 79 | #define P_ENDIF 23 // .endif 80 | #define P_FAIL 24 // .fail 81 | #define P_ZP 25 // .zp 82 | #define P_BSS 26 // .bss 83 | #define P_CODE 27 // .code 84 | #define P_DATA 28 // .data 85 | #define P_DEFCHR 29 // .defchr 86 | #define P_FUNC 30 // .func 87 | #define P_IFDEF 31 // .ifdef 88 | #define P_IFNDEF 32 // .ifndef 89 | #define P_VRAM 33 // .vram 90 | #define P_PAL 34 // .pal 91 | #define P_DEFPAL 35 // .defpal 92 | #define P_DEFSPR 36 // .defspr 93 | #define P_INESPRG 37 // .inesprg 94 | #define P_INESCHR 38 // .ineschr 95 | #define P_INESMAP 39 // .inesmap 96 | #define P_INESMIR 40 // .inesmir 97 | #define P_OPT 41 // .opt 98 | #define P_INCTILE 42 // .inctile 99 | #define P_INCMAP 43 // .incmap 100 | #define P_MML 44 // .mml 101 | #define P_PROC 45 // .proc 102 | #define P_ENDP 46 // .endp 103 | #define P_PGROUP 47 // .procgroup 104 | #define P_ENDPG 48 // .endprocgroup 105 | #define P_CALL 49 // .call 106 | 107 | /* symbol flags */ 108 | #define MDEF 3 /* multiply defined */ 109 | #define UNDEF 1 /* undefined - may be zero page */ 110 | #define IFUNDEF 2 /* declared in a .if expression */ 111 | #define DEFABS 4 /* defined - two byte address */ 112 | #define MACRO 5 /* used for a macro name */ 113 | #define FUNC 6 /* used for a function */ 114 | 115 | /* operation code flags */ 116 | #define PSEUDO 0x0008000 117 | #define CLASS1 0x0010000 118 | #define CLASS2 0x0020000 119 | #define CLASS3 0x0040000 120 | #define CLASS5 0x0080000 121 | #define CLASS6 0x0100000 122 | #define CLASS7 0x0200000 123 | #define CLASS8 0x0400000 124 | #define CLASS9 0x0800000 125 | #define CLASS10 0x1000000 126 | #define ACC 0x0000001 127 | #define IMM 0x0000002 128 | #define ZP 0x0000004 129 | #define ZP_X 0x0000008 130 | #define ZP_Y 0x0000010 131 | #define ZP_IND 0x0000020 132 | #define ZP_IND_X 0x0000040 133 | #define ZP_IND_Y 0x0000080 134 | #define ABS 0x0000100 135 | #define ABS_X 0x0000200 136 | #define ABS_Y 0x0000400 137 | #define ABS_IND 0x0000800 138 | #define ABS_IND_X 0x0001000 139 | 140 | /* pass flags */ 141 | #define FIRST_PASS 0 142 | #define LAST_PASS 1 143 | 144 | /* structs */ 145 | typedef struct t_opcode { 146 | struct t_opcode *next; 147 | char *name; 148 | void (*proc)(int *); 149 | int flag; 150 | int value; 151 | int type_idx; 152 | } t_opcode; 153 | 154 | typedef struct t_input_info { 155 | FILE *fp; 156 | int lnum; 157 | int if_level; 158 | char name[116]; 159 | } t_input_info; 160 | 161 | typedef struct t_proc { 162 | struct t_proc *next; 163 | struct t_proc *link; 164 | struct t_proc *group; 165 | int old_bank; 166 | int bank; 167 | int org; 168 | int base; 169 | int size; 170 | int call; 171 | int type; 172 | int refcnt; 173 | char name[SBOLSZ]; 174 | } t_proc; 175 | 176 | typedef struct t_symbol { 177 | struct t_symbol *next; 178 | struct t_symbol *local; 179 | struct t_proc *proc; 180 | int type; 181 | int value; 182 | int bank; 183 | int page; 184 | int nb; 185 | int size; 186 | int vram; 187 | int pal; 188 | int refcnt; 189 | int reserved; 190 | int data_type; 191 | int data_size; 192 | char name[SBOLSZ]; 193 | } t_symbol; 194 | 195 | typedef struct t_line { 196 | struct t_line *next; 197 | char *data; 198 | } t_line; 199 | 200 | typedef struct t_macro { 201 | struct t_macro *next; 202 | struct t_line *line; 203 | char name[SBOLSZ]; 204 | } t_macro; 205 | 206 | typedef struct t_func { 207 | struct t_func *next; 208 | char line[128]; 209 | char name[SBOLSZ]; 210 | } t_func; 211 | 212 | typedef struct t_tile { 213 | struct t_tile *next; 214 | unsigned char *data; 215 | unsigned int crc; 216 | int index; 217 | } t_tile; 218 | 219 | typedef struct t_machine { 220 | int type; 221 | char *asm_name; 222 | char *asm_title; 223 | char *rom_ext; 224 | char *include_env; 225 | unsigned int zp_limit; 226 | unsigned int ram_limit; 227 | unsigned int ram_base; 228 | unsigned int ram_page; 229 | unsigned int ram_bank; 230 | struct t_opcode *inst; 231 | struct t_opcode *pseudo_inst; 232 | int (*pack_8x8_tile)(unsigned char *, void *, int, int); 233 | int (*pack_16x16_tile)(unsigned char *, void *, int, int); 234 | int (*pack_16x16_sprite)(unsigned char *, void *, int, int); 235 | void (*write_header)(FILE *, int); 236 | } MACHINE; 237 | 238 | -------------------------------------------------------------------------------- /nesasmsrc/expr.h: -------------------------------------------------------------------------------- 1 | /* value types */ 2 | #define T_DECIMAL 0 3 | #define T_HEXA 1 4 | #define T_BINARY 2 5 | #define T_CHAR 3 6 | #define T_SYMBOL 4 7 | #define T_PC 5 8 | 9 | /* operators */ 10 | #define OP_START 0 11 | #define OP_OPEN 1 12 | #define OP_ADD 2 13 | #define OP_SUB 3 14 | #define OP_MUL 4 15 | #define OP_DIV 5 16 | #define OP_MOD 6 17 | #define OP_NEG 7 18 | #define OP_SHL 8 19 | #define OP_SHR 9 20 | #define OP_OR 10 21 | #define OP_XOR 11 22 | #define OP_AND 12 23 | #define OP_COM 13 24 | #define OP_NOT 14 25 | #define OP_EQUAL 15 26 | #define OP_NOT_EQUAL 16 27 | #define OP_LOWER 17 28 | #define OP_LOWER_EQUAL 18 29 | #define OP_HIGHER 19 30 | #define OP_HIGHER_EQUAL 20 31 | #define OP_DEFINED 21 32 | #define OP_HIGH 22 33 | #define OP_LOW 23 34 | #define OP_PAGE 24 35 | #define OP_BANK 25 36 | #define OP_VRAM 26 37 | #define OP_PAL 27 38 | #define OP_SIZEOF 28 39 | 40 | /* operator priority */ 41 | int op_pri[] = { 42 | 0 /* START */, 0 /* OPEN */, 43 | 7 /* ADD */, 7 /* SUB */, 8 /* MUL */, 8 /* DIV */, 44 | 8 /* MOD */, 10 /* NEG */, 6 /* SHL */, 6 /* SHR */, 45 | 1 /* OR */, 2 /* XOR */, 3 /* AND */, 10 /* COM */, 46 | 9 /* NOT */, 4 /* = */, 4 /* <> */, 5 /* < */, 47 | 5 /* <= */, 5 /* > */, 5 /* >= */, 48 | 10 /* DEFIN.*/, 10 /* HIGH */, 10 /* LOW */, 10 /* PAGE */, 49 | 10 /* BANK */, 10 /* VRAM */, 10 /* PAL */, 10 /* SIZEOF*/ 50 | }; 51 | 52 | unsigned int op_stack[64] = { OP_START }; /* operator stack */ 53 | unsigned int val_stack[64]; /* value stack */ 54 | int op_idx, val_idx; /* index in the operator and value stacks */ 55 | int need_operator; /* when set await an operator, else await a value */ 56 | unsigned char *expr; /* pointer to the expression string */ 57 | unsigned char *expr_stack[16]; /* expression stack */ 58 | struct t_symbol *expr_lablptr; /* pointer to the lastest label */ 59 | int expr_lablcnt; /* number of label seen in an expression */ 60 | char *keyword[8] = { /* predefined functions */ 61 | "\7DEFINED", 62 | "\4HIGH", "\3LOW", 63 | "\4PAGE", "\4BANK", 64 | "\4VRAM", "\3PAL", 65 | "\6SIZEOF" 66 | }; 67 | 68 | -------------------------------------------------------------------------------- /nesasmsrc/externs.h: -------------------------------------------------------------------------------- 1 | extern unsigned char rom[128][XXX_BANK_SIZE]; 2 | extern unsigned char map[128][XXX_BANK_SIZE]; 3 | extern char bank_name[128][64]; 4 | extern int bank_loccnt[4][256]; 5 | extern int bank_page[4][256]; 6 | extern int max_zp; /* higher used address in zero page */ 7 | extern int max_bss; /* higher used address in ram */ 8 | extern int max_bank; /* last bank used */ 9 | extern int data_loccnt; /* data location counter */ 10 | extern int data_size; /* size of binary output (in bytes) */ 11 | extern int data_level; /* data output level, must be <= listlevel to be outputed */ 12 | extern int loccnt; /* location counter */ 13 | extern int bank; /* current bank */ 14 | extern int bank_base; /* bank base index */ 15 | extern int bank_limit; /* bank limit */ 16 | extern int rom_limit; /* rom max. size in bytes */ 17 | extern int page; /* page */ 18 | extern int rsbase; /* .rs counter */ 19 | extern int section; /* current section: S_ZP, S_BSS, S_CODE or S_DATA */ 20 | extern int section_bank[4]; /* current bank for each section */ 21 | extern int in_if; /* true if in a '.if' statement */ 22 | extern int if_expr; /* set when parsing an .if expression */ 23 | extern int if_level; /* level of nested .if's */ 24 | extern int skip_lines; /* when true skip lines */ 25 | extern int continued_line; /* set when a line is the continuation of another line */ 26 | extern int pcx_w, pcx_h; /* PCX dimensions */ 27 | extern int pcx_nb_colors; /* number of colors (16/256) in the PCX */ 28 | extern int pcx_nb_args; /* number of argument */ 29 | extern unsigned int pcx_arg[8]; /* PCX args array */ 30 | extern unsigned char *pcx_buf; /* pointer to the PCX buffer */ 31 | extern unsigned char pcx_pal[256][3]; /* palette */ 32 | extern unsigned char *expr; /* expression string pointer */ 33 | extern int mopt; 34 | extern int in_macro; 35 | extern int expand_macro; 36 | extern char marg[8][10][80]; 37 | extern int midx; 38 | extern int mcounter, mcntmax; 39 | extern int mcntstack[8]; 40 | extern struct t_line *mstack[8]; 41 | extern struct t_line *mlptr; 42 | extern struct t_macro *macro_tbl[256]; 43 | extern struct t_macro *mptr; 44 | extern struct t_func *func_tbl[256]; 45 | extern struct t_func *func_ptr; 46 | extern struct t_proc *proc_ptr; 47 | extern int proc_nb; 48 | extern char func_arg[8][10][80]; 49 | extern int func_idx; 50 | extern int infile_error; 51 | extern int infile_num; 52 | extern FILE *out_fp; /* file pointers, output */ 53 | extern FILE *in_fp; /* input */ 54 | extern FILE *lst_fp; /* listing */ 55 | extern struct t_input_info input_file[8]; 56 | extern struct t_machine *machine; 57 | extern struct t_machine nes; 58 | extern struct t_machine pce; 59 | extern struct t_opcode *inst_tbl[256]; /* instructions hash table */ 60 | extern struct t_symbol *hash_tbl[256]; /* label hash table */ 61 | extern struct t_symbol *lablptr; /* label pointer into symbol table */ 62 | extern struct t_symbol *glablptr; /* pointer to the latest defined global symbol */ 63 | extern struct t_symbol *lastlabl; /* last label we have seen */ 64 | extern struct t_symbol *bank_glabl[4][256]; /* latest global label in each bank */ 65 | extern char hex[]; /* hexadecimal character buffer */ 66 | extern int stop_pass; /* stop the program; set by fatal_error() */ 67 | extern int errcnt; /* error counter */ 68 | extern void (*opproc)(int *); /* instruction gen proc */ 69 | extern int opflg; /* instruction flags */ 70 | extern int opval; /* instruction value */ 71 | extern int optype; /* instruction type */ 72 | extern char opext; /* instruction extension (.l or .h) */ 73 | extern int pass; /* pass counter */ 74 | extern char prlnbuf[]; /* input line buffer */ 75 | extern char tmplnbuf[]; /* temporary line buffer */ 76 | extern int slnum; /* source line number counter */ 77 | extern char symbol[]; /* temporary symbol storage */ 78 | extern int undef; /* undefined symbol in expression flag */ 79 | extern unsigned int value; /* operand field value */ 80 | extern int mlist_opt; /* macro listing main flag */ 81 | extern int xlist; /* listing file main flag */ 82 | extern int list_level; /* output level */ 83 | extern int asm_opt[8]; /* assembler option state */ 84 | extern int opvaltab[6][16]; 85 | 86 | -------------------------------------------------------------------------------- /nesasmsrc/func.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "defs.h" 6 | #include "externs.h" 7 | #include "protos.h" 8 | 9 | struct t_func *func_tbl[256]; 10 | struct t_func *func_ptr; 11 | char func_line[128]; 12 | char func_arg[8][10][80]; 13 | int func_idx; 14 | 15 | 16 | /* ---- 17 | * do_func() 18 | * ---- 19 | * .func pseudo 20 | */ 21 | 22 | void 23 | do_func(int *ip) 24 | { 25 | if (pass == LAST_PASS) 26 | println(); 27 | else { 28 | /* error checking */ 29 | if (lablptr == NULL) { 30 | error("No name for this function!"); 31 | return; 32 | } 33 | if (lablptr->refcnt) { 34 | switch (lablptr->type) { 35 | case MACRO: 36 | fatal_error("Symbol already used by a macro!"); 37 | 38 | case FUNC: 39 | fatal_error("Function already defined!"); 40 | return; 41 | 42 | default: 43 | fatal_error("Symbol already used by a label!"); 44 | return; 45 | } 46 | } 47 | 48 | /* install this new function in the hash table */ 49 | if (!func_install(*ip)) 50 | return; 51 | } 52 | } 53 | 54 | /* search a function */ 55 | 56 | int 57 | func_look(void) 58 | { 59 | int hash; 60 | 61 | /* search the function in the hash table */ 62 | hash = symhash(); 63 | func_ptr = func_tbl[hash]; 64 | while (func_ptr) { 65 | if (!strcmp(&symbol[1], func_ptr->name)) 66 | break; 67 | func_ptr = func_ptr->next; 68 | } 69 | 70 | /* ok */ 71 | if (func_ptr) 72 | return (1); 73 | 74 | /* didn't find a function with this name */ 75 | return (0); 76 | } 77 | 78 | /* install a function in the hash table */ 79 | 80 | int 81 | func_install(int ip) 82 | { 83 | int hash; 84 | 85 | /* mark the function name as reserved */ 86 | lablptr->type = FUNC; 87 | 88 | /* check function name syntax */ 89 | if (strchr(&symbol[1], '.')) { 90 | error("Invalid function name!"); 91 | return (0); 92 | } 93 | 94 | /* extract function body */ 95 | if (func_extract(ip) == -1) 96 | return (0); 97 | 98 | /* allocate a new func struct */ 99 | if ((func_ptr = (void *)malloc(sizeof(struct t_func))) == NULL) { 100 | error("Out of memory!"); 101 | return (0); 102 | } 103 | 104 | /* initialize it */ 105 | strcpy(func_ptr->name, &symbol[1]); 106 | strcpy(func_ptr->line, func_line); 107 | hash = symhash(); 108 | func_ptr->next = func_tbl[hash]; 109 | func_tbl[hash] = func_ptr; 110 | 111 | /* ok */ 112 | return (1); 113 | } 114 | 115 | /* extract function body */ 116 | 117 | int 118 | func_extract(int ip) 119 | { 120 | char *ptr; 121 | char c; 122 | int i, arg, max_arg; 123 | int end; 124 | 125 | /* skip spaces */ 126 | while (isspace(prlnbuf[ip])) 127 | ip++; 128 | 129 | /* get function body */ 130 | ptr = func_line; 131 | max_arg = 0; 132 | end = 0; 133 | i = 0; 134 | 135 | while (!end) { 136 | c = prlnbuf[ip++]; 137 | switch (c) { 138 | /* end of line */ 139 | case ';': 140 | case '\0': 141 | *ptr++ = '\0'; 142 | end = 1; 143 | break; 144 | 145 | /* function arg */ 146 | case '\\': 147 | *ptr++ = c; 148 | i++; 149 | c = prlnbuf[ip++]; 150 | if ((c < '1') || (c > '9')) { 151 | error("Invalid function argument!"); 152 | return (-1); 153 | } 154 | arg = c - '1'; 155 | if (max_arg < arg) 156 | max_arg = arg; 157 | 158 | /* other */ 159 | default: 160 | *ptr++ = c; 161 | i++; 162 | if (i == 127) { 163 | error("Function line too long!"); 164 | return (-1); 165 | } 166 | break; 167 | } 168 | } 169 | 170 | /* return the number of args */ 171 | return (max_arg); 172 | } 173 | 174 | /* extract function args */ 175 | 176 | int 177 | func_getargs(void) 178 | { 179 | char c, *ptr, *line; 180 | int arg, level, space, flag; 181 | int i, x; 182 | 183 | /* can not nest too much macros */ 184 | if (func_idx == 7) { 185 | error("Too many nested function calls!"); 186 | return (0); 187 | } 188 | 189 | /* skip spaces */ 190 | while (isspace(*expr)) 191 | expr++; 192 | 193 | /* function args must be enclosed in parenthesis */ 194 | if (*expr++ != '(') 195 | return (0); 196 | 197 | /* initialize args */ 198 | line = NULL; 199 | ptr = func_arg[func_idx][0]; 200 | arg = 0; 201 | 202 | for (i = 0; i < 9; i++) 203 | func_arg[func_idx][i][0] = '\0'; 204 | 205 | /* get args one by one */ 206 | for (;;) { 207 | /* skip spaces */ 208 | while (isspace(*expr)) 209 | expr++; 210 | 211 | c = *expr++; 212 | switch (c) { 213 | /* empty arg */ 214 | case ',': 215 | arg++; 216 | ptr = func_arg[func_idx][arg]; 217 | if (arg == 9) { 218 | error("Too many arguments for a function!"); 219 | return (0); 220 | } 221 | break; 222 | 223 | /* end of line */ 224 | case ';': 225 | case '\0': 226 | error("Syntax error in function call!"); 227 | return (0); 228 | 229 | /* end of function */ 230 | case ')': 231 | return (1); 232 | 233 | /* arg */ 234 | default: 235 | space = 0; 236 | level = 0; 237 | flag = 0; 238 | i = 0; 239 | x = 0; 240 | for (;;) { 241 | if (c == '\0') { 242 | if (flag == 0) 243 | break; 244 | else { 245 | flag = 0; 246 | c = *expr++; 247 | continue; 248 | } 249 | } 250 | else if (c == ';') { 251 | break; 252 | } 253 | else if (c == ',') { 254 | if (level == 0) 255 | break; 256 | } 257 | else if (c == '\\') { 258 | if (func_idx == 0) { 259 | error("Syntax error!"); 260 | return (0); 261 | } 262 | c = *expr++; 263 | if (c < '1' || c > '9') { 264 | error("Invalid function argument index!"); 265 | return (0); 266 | } 267 | line = func_arg[func_idx - 1][c - '1']; 268 | flag = 1; 269 | c = *line++; 270 | continue; 271 | } 272 | else if (c == '(') { 273 | level++; 274 | } 275 | else if (c == ')') { 276 | if (level == 0) 277 | break; 278 | level--; 279 | } 280 | if (space) { 281 | if (c != ' ') { 282 | while (i < x) 283 | ptr[i++] = ' '; 284 | ptr[i++] = c; 285 | space = 0; 286 | } 287 | } 288 | else if (c == ' ') { 289 | space = 1; 290 | } 291 | else { 292 | ptr[i++] = c; 293 | } 294 | if (i == 80) { 295 | error("Invalid function argument length!"); 296 | return (0); 297 | } 298 | x++; 299 | if (flag) 300 | c = *line++; 301 | else 302 | c = *expr++; 303 | } 304 | ptr[i] = '\0'; 305 | expr--; 306 | break; 307 | } 308 | } 309 | } 310 | 311 | -------------------------------------------------------------------------------- /nesasmsrc/input.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "defs.h" 6 | #include "externs.h" 7 | #include "protos.h" 8 | 9 | int infile_error; 10 | int infile_num; 11 | struct t_input_info input_file[8]; 12 | char incpath[10][128]; 13 | 14 | 15 | /* ---- 16 | * init_path() 17 | * ---- 18 | * init the include path 19 | */ 20 | 21 | void 22 | init_path(void) 23 | { 24 | char *p,*pl; 25 | int i, l; 26 | 27 | p = getenv(machine->include_env); 28 | 29 | if (p == NULL) 30 | return; 31 | 32 | for (i = 0; i < 10; i++) { 33 | 34 | pl = strchr(p, ';'); 35 | 36 | if (pl == NULL) 37 | l = strlen(p); 38 | else 39 | l = pl-p; 40 | 41 | if (l == 0) { 42 | incpath[i][0] = '\0'; 43 | } else { 44 | strncpy(incpath[i],p,l); 45 | p += l; 46 | while (*p == ';') p++; 47 | } 48 | 49 | if (incpath[i][strlen(incpath[i])] != PATH_SEPARATOR) { 50 | strcat(incpath[i], PATH_SEPARATOR_STRING); 51 | } 52 | } 53 | } 54 | 55 | 56 | /* ---- 57 | * readline() 58 | * ---- 59 | * read and format an input line. 60 | */ 61 | 62 | int 63 | readline(void) 64 | { 65 | char *ptr, *arg, num[8]; 66 | int j, n; 67 | int i; /* pointer into prlnbuf */ 68 | int c; /* current character */ 69 | int temp; /* temp used for line number conversion */ 70 | 71 | start: 72 | for (i = 0; i < LAST_CH_POS; i++) 73 | prlnbuf[i] = ' '; 74 | 75 | /* if 'expand_macro' is set get a line from macro buffer instead */ 76 | if (expand_macro) { 77 | if (mlptr == NULL) { 78 | while (mlptr == NULL) { 79 | midx--; 80 | mlptr = mstack[midx]; 81 | mcounter = mcntstack[midx]; 82 | if (midx == 0) { 83 | mlptr = NULL; 84 | expand_macro = 0; 85 | break; 86 | } 87 | } 88 | } 89 | 90 | /* expand line */ 91 | if (mlptr) { 92 | i = SFIELD; 93 | ptr = mlptr->data; 94 | for (;;) { 95 | c = *ptr++; 96 | if (c == '\0') 97 | break; 98 | if (c != '\\') 99 | prlnbuf[i++] = c; 100 | else { 101 | c = *ptr++; 102 | prlnbuf[i] = '\0'; 103 | 104 | /* \@ */ 105 | if (c == '@') { 106 | n = 5; 107 | sprintf(num, "%05i", mcounter); 108 | arg = num; 109 | } 110 | 111 | /* \# */ 112 | else if (c == '#') { 113 | for (j = 9; j > 0; j--) 114 | if (strlen(marg[midx][j - 1])) 115 | break; 116 | n = 1; 117 | sprintf(num, "%i", j); 118 | arg = num; 119 | } 120 | 121 | /* \?1 - \?9 */ 122 | else if (c == '?') { 123 | c = *ptr++; 124 | if (c >= '1' && c <= '9') { 125 | n = 1; 126 | sprintf(num, "%i", macro_getargtype(marg[midx][c - '1'])); 127 | arg = num; 128 | } 129 | else { 130 | error("Invalid macro argument index!"); 131 | return (-1); 132 | } 133 | } 134 | 135 | /* \1 - \9 */ 136 | else if (c >= '1' && c <= '9') { 137 | j = c - '1'; 138 | n = strlen(marg[midx][j]); 139 | arg = marg[midx][j]; 140 | } 141 | 142 | /* unknown macro special command */ 143 | else { 144 | error("Invalid macro argument index!"); 145 | return (-1); 146 | } 147 | 148 | /* check for line overflow */ 149 | if ((i + n) >= LAST_CH_POS - 1) { 150 | error("Invalid line length!"); 151 | return (-1); 152 | } 153 | 154 | /* copy macro string */ 155 | strncpy(&prlnbuf[i], arg, n); 156 | i += n; 157 | } 158 | if (i >= LAST_CH_POS - 1) 159 | i = LAST_CH_POS - 1; 160 | } 161 | prlnbuf[i] = '\0'; 162 | mlptr = mlptr->next; 163 | return (0); 164 | } 165 | } 166 | 167 | /* put source line number into prlnbuf */ 168 | i = 4; 169 | temp = ++slnum; 170 | while (temp != 0) { 171 | prlnbuf[i--] = temp % 10 + '0'; 172 | temp /= 10; 173 | } 174 | 175 | /* get a line */ 176 | i = SFIELD; 177 | c = getc(in_fp); 178 | if (c == EOF) { 179 | if (close_input()) 180 | return (-1); 181 | goto start; 182 | } 183 | for (;;) { 184 | /* check for the end of line */ 185 | if (c == '\r') { 186 | c = getc(in_fp); 187 | if (c == '\n' || c == EOF) 188 | break; 189 | ungetc(c, in_fp); 190 | break; 191 | } 192 | if (c == '\n' || c == EOF) 193 | break; 194 | 195 | /* store char in the line buffer */ 196 | prlnbuf[i] = c; 197 | i += (i < LAST_CH_POS) ? 1 : 0; 198 | 199 | /* expand tab char to space */ 200 | if (c == '\t') { 201 | prlnbuf[--i] = ' '; 202 | i += (8 - ((i - SFIELD) % 8)); 203 | } 204 | 205 | /* get next char */ 206 | c = getc(in_fp); 207 | } 208 | prlnbuf[i] = '\0'; 209 | return(0); 210 | } 211 | 212 | /* ---- 213 | * open_input() 214 | * ---- 215 | * open input files - up to 7 levels. 216 | */ 217 | 218 | int 219 | open_input(char *name) 220 | { 221 | FILE *fp; 222 | char *p; 223 | char temp[128]; 224 | int i; 225 | 226 | /* only 7 nested input files */ 227 | if (infile_num == 7) { 228 | error("Too many include levels, max. 7!"); 229 | return (1); 230 | } 231 | 232 | /* backup current input file infos */ 233 | if (infile_num) { 234 | input_file[infile_num].lnum = slnum; 235 | input_file[infile_num].fp = in_fp; 236 | } 237 | 238 | /* get a copy of the file name */ 239 | strcpy(temp, name); 240 | 241 | /* auto add the .asm file extension */ 242 | if ((p = strrchr(temp, '.')) != NULL) { 243 | if (strchr(p, PATH_SEPARATOR)) 244 | strcat(temp, ".asm"); 245 | } 246 | else { 247 | strcat(temp, ".asm"); 248 | } 249 | 250 | /* check if this file is already opened */ 251 | if (infile_num) { 252 | for (i = 1; i < infile_num; i++) { 253 | if (!strcmp(input_file[i].name, temp)) { 254 | error("Repeated include file!"); 255 | return (1); 256 | } 257 | } 258 | } 259 | 260 | /* open the file */ 261 | if ((fp = open_file(temp, "r")) == NULL) 262 | return (-1); 263 | 264 | /* update input file infos */ 265 | in_fp = fp; 266 | slnum = 0; 267 | infile_num++; 268 | input_file[infile_num].fp = fp; 269 | input_file[infile_num].if_level = if_level; 270 | strcpy(input_file[infile_num].name, temp); 271 | if ((pass == LAST_PASS) && (xlist) && (list_level)) 272 | fprintf(lst_fp, "#[%i] %s\n", infile_num, input_file[infile_num].name); 273 | 274 | /* ok */ 275 | return (0); 276 | } 277 | 278 | 279 | /* ---- 280 | * close_input() 281 | * ---- 282 | * close an input file, return -1 if no more files in the stack. 283 | */ 284 | 285 | int 286 | close_input(void) 287 | { 288 | if (proc_ptr) { 289 | fatal_error("Incomplete PROC!"); 290 | return (-1); 291 | } 292 | if (in_macro) { 293 | fatal_error("Incomplete MACRO definition!"); 294 | return (-1); 295 | } 296 | if (input_file[infile_num].if_level != if_level) { 297 | fatal_error("Incomplete IF/ENDIF statement!"); 298 | return (-1); 299 | } 300 | if (infile_num <= 1) 301 | return (-1); 302 | 303 | fclose(in_fp); 304 | infile_num--; 305 | infile_error = -1; 306 | slnum = input_file[infile_num].lnum; 307 | in_fp = input_file[infile_num].fp; 308 | if ((pass == LAST_PASS) && (xlist) && (list_level)) 309 | fprintf(lst_fp, "#[%i] %s\n", infile_num, input_file[infile_num].name); 310 | 311 | /* ok */ 312 | return (0); 313 | } 314 | 315 | 316 | /* ---- 317 | * open_file() 318 | * ---- 319 | * open a file - browse paths 320 | */ 321 | 322 | FILE * 323 | open_file(char *name, char *mode) 324 | { 325 | FILE *fileptr; 326 | char testname[256]; 327 | int i; 328 | 329 | fileptr = fopen(name, mode); 330 | if (fileptr != NULL) return(fileptr); 331 | 332 | for (i = 0; i < 10; i++) { 333 | if (strlen(incpath[i])) { 334 | strcpy(testname, incpath[i]); 335 | strcat(testname, name); 336 | 337 | fileptr = fopen(testname, mode); 338 | if (fileptr != NULL) break; 339 | } 340 | } 341 | 342 | return (fileptr); 343 | } 344 | 345 | -------------------------------------------------------------------------------- /nesasmsrc/inst.h: -------------------------------------------------------------------------------- 1 | 2 | /* instruction table */ 3 | struct t_opcode base_inst[57] = { 4 | {NULL, "ADC", class4, IMM|ZP|ZP_X|ZP_IND_X|ZP_IND_Y|ABS|ABS_X|ABS_Y, 0x61, 0}, //BJP removed ZP_IND mode 5 | {NULL, "AND", class4, IMM|ZP|ZP_X|ZP_IND_X|ZP_IND_Y|ABS|ABS_X|ABS_Y, 0x21, 0}, //BJP removed ZP_IND mode 6 | {NULL, "ASL", class4, ACC|ZP|ZP_X|ABS|ABS_X, 0x02, 0}, 7 | {NULL, "BCC", class2, 0, 0x90, 0}, 8 | {NULL, "BCS", class2, 0, 0xB0, 0}, 9 | {NULL, "BEQ", class2, 0, 0xF0, 0}, 10 | {NULL, "BIT", class4, IMM|ZP|ZP_X|ABS|ABS_X, 0x00, 2}, 11 | {NULL, "BMI", class2, 0, 0x30, 0}, 12 | {NULL, "BNE", class2, 0, 0xD0, 0}, 13 | {NULL, "BPL", class2, 0, 0x10, 0}, 14 | {NULL, "BRK", class1, 0, 0x00, 0}, 15 | {NULL, "BVC", class2, 0, 0x50, 0}, 16 | {NULL, "BVS", class2, 0, 0x70, 0}, 17 | {NULL, "CLC", class1, 0, 0x18, 0}, 18 | {NULL, "CLD", class1, 0, 0xD8, 0}, 19 | {NULL, "CLI", class1, 0, 0x58, 0}, 20 | {NULL, "CLV", class1, 0, 0xB8, 0}, 21 | {NULL, "CMP", class4, IMM|ZP|ZP_X|ZP_IND_X|ZP_IND_Y|ABS|ABS_X|ABS_Y, 0xC1, 0}, //BJP removed ZP_IND mode 22 | {NULL, "CPX", class4, IMM|ZP|ABS, 0xE0, 1}, 23 | {NULL, "CPY", class4, IMM|ZP|ABS, 0xC0, 1}, 24 | {NULL, "DEC", class4, ACC|ZP|ZP_X|ABS|ABS_X, 0x00, 3}, 25 | {NULL, "DEX", class1, 0, 0xCA, 0}, 26 | {NULL, "DEY", class1, 0, 0x88, 0}, 27 | {NULL, "EOR", class4, IMM|ZP|ZP_X|ZP_IND_X|ZP_IND_Y|ABS|ABS_X|ABS_Y, 0x41, 0}, //BJP removed ZP_IND mode 28 | {NULL, "INC", class4, ACC|ZP|ZP_X|ABS|ABS_X, 0x00, 4}, 29 | {NULL, "INX", class1, 0, 0xE8, 0}, 30 | {NULL, "INY", class1, 0, 0xC8, 0}, 31 | {NULL, "JMP", class4, ABS|ABS_IND|ABS_IND_X, 0x40, 0}, 32 | {NULL, "JSR", class4, ABS, 0x14, 0}, 33 | {NULL, "LDA", class4, IMM|ZP|ZP_X|ZP_IND_X|ZP_IND_Y|ABS|ABS_X|ABS_Y, 0xA1, 0}, //BJP removed ZP_IND mode 34 | {NULL, "LDX", class4, IMM|ZP|ZP_Y|ABS|ABS_Y, 0xA2, 1}, 35 | {NULL, "LDY", class4, IMM|ZP|ZP_X|ABS|ABS_X, 0xA0, 1}, 36 | {NULL, "LSR", class4, ACC|ZP|ZP_X|ABS|ABS_X, 0x42, 0}, 37 | {NULL, "NOP", class1, 0, 0xEA, 0}, 38 | {NULL, "ORA", class4, IMM|ZP|ZP_X|ZP_IND_X|ZP_IND_Y|ABS|ABS_X|ABS_Y, 0x01, 0}, //BJP removed ZP_IND mode 39 | {NULL, "PHA", class1, 0, 0x48, 0}, 40 | {NULL, "PHP", class1, 0, 0x08, 0}, 41 | {NULL, "PLA", class1, 0, 0x68, 0}, 42 | {NULL, "PLP", class1, 0, 0x28, 0}, 43 | {NULL, "ROL", class4, ACC|ZP|ZP_X|ABS|ABS_X, 0x22, 0}, 44 | {NULL, "ROR", class4, ACC|ZP|ZP_X|ABS|ABS_X, 0x62, 0}, 45 | {NULL, "RTI", class1, 0, 0x40, 0}, 46 | {NULL, "RTS", class1, 0, 0x60, 0}, 47 | {NULL, "SBC", class4, IMM|ZP|ZP_X|ZP_IND_X|ZP_IND_Y|ABS|ABS_X|ABS_Y, 0xE1, 0}, //BJP removed ZP_IND mode 48 | {NULL, "SEC", class1, 0, 0x38, 0}, 49 | {NULL, "SED", class1, 0, 0xF8, 0}, 50 | {NULL, "SEI", class1, 0, 0x78, 0}, 51 | {NULL, "STA", class4, ZP|ZP_X|ZP_IND_X|ZP_IND_Y|ABS|ABS_X|ABS_Y, 0x81, 0}, //BJP removed ZP_IND mode 52 | {NULL, "STX", class4, ZP|ZP_Y|ABS, 0x82, 0}, 53 | {NULL, "STY", class4, ZP|ZP_X|ABS, 0x80, 0}, 54 | {NULL, "TAX", class1, 0, 0xAA, 0}, 55 | {NULL, "TAY", class1, 0, 0xA8, 0}, 56 | {NULL, "TSX", class1, 0, 0xBA, 0}, 57 | {NULL, "TXA", class1, 0, 0x8A, 0}, 58 | {NULL, "TXS", class1, 0, 0x9A, 0}, 59 | {NULL, "TYA", class1, 0, 0x98, 0}, 60 | {NULL, NULL, NULL, 0, 0, 0} 61 | }; 62 | 63 | /* pseudo instruction table */ 64 | struct t_opcode base_pseudo[77] = { 65 | {NULL, "=", do_equ, PSEUDO, P_EQU, 0}, 66 | 67 | {NULL, "BANK", do_bank, PSEUDO, P_BANK, 0}, 68 | {NULL, "BSS", do_section, PSEUDO, P_BSS, S_BSS}, 69 | {NULL, "BYTE", do_db, PSEUDO, P_DB, 0}, 70 | {NULL, "CALL", do_call, PSEUDO, P_CALL, 0}, 71 | {NULL, "CODE", do_section, PSEUDO, P_CODE, S_CODE}, 72 | {NULL, "DATA", do_section, PSEUDO, P_DATA, S_DATA}, 73 | {NULL, "DB", do_db, PSEUDO, P_DB, 0}, 74 | {NULL, "DW", do_dw, PSEUDO, P_DW, 0}, 75 | {NULL, "DS", do_ds, PSEUDO, P_DS, 0}, 76 | {NULL, "ELSE", do_else, PSEUDO, P_ELSE, 0}, 77 | {NULL, "ENDIF", do_endif, PSEUDO, P_ENDIF, 0}, 78 | {NULL, "ENDM", do_endm, PSEUDO, P_ENDM, 0}, 79 | {NULL, "ENDP", do_endp, PSEUDO, P_ENDP, P_PROC}, 80 | {NULL, "ENDPROCGROUP", do_endp, PSEUDO, P_ENDPG, P_PGROUP}, 81 | {NULL, "EQU", do_equ, PSEUDO, P_EQU, 0}, 82 | {NULL, "FAIL", do_fail, PSEUDO, P_FAIL, 0}, 83 | {NULL, "FUNC", do_func, PSEUDO, P_FUNC, 0}, 84 | {NULL, "IF", do_if, PSEUDO, P_IF, 0}, 85 | {NULL, "IFDEF", do_ifdef, PSEUDO, P_IFDEF, 1}, 86 | {NULL, "IFNDEF", do_ifdef, PSEUDO, P_IFNDEF, 0}, 87 | {NULL, "INCBIN", do_incbin, PSEUDO, P_INCBIN, 0}, 88 | {NULL, "INCLUDE", do_include, PSEUDO, P_INCLUDE, 0}, 89 | {NULL, "INCCHR", do_incchr, PSEUDO, P_INCCHR, 0xEA}, 90 | {NULL, "LIST", do_list, PSEUDO, P_LIST, 0}, 91 | {NULL, "MAC", do_macro, PSEUDO, P_MACRO, 0}, 92 | {NULL, "MACRO", do_macro, PSEUDO, P_MACRO, 0}, 93 | {NULL, "MLIST", do_mlist, PSEUDO, P_MLIST, 0}, 94 | {NULL, "NOLIST", do_nolist, PSEUDO, P_NOLIST, 0}, 95 | {NULL, "NOMLIST", do_nomlist, PSEUDO, P_NOMLIST, 0}, 96 | {NULL, "OPT", do_opt, PSEUDO, P_OPT, 0}, 97 | {NULL, "ORG", do_org, PSEUDO, P_ORG, 0}, 98 | {NULL, "PAGE", do_page, PSEUDO, P_PAGE, 0}, 99 | {NULL, "PROC", do_proc, PSEUDO, P_PROC, P_PROC}, 100 | {NULL, "PROCGROUP", do_proc, PSEUDO, P_PGROUP, P_PGROUP}, 101 | {NULL, "RSSET", do_rsset, PSEUDO, P_RSSET, 0}, 102 | {NULL, "RS", do_rs, PSEUDO, P_RS, 0}, 103 | {NULL, "WORD", do_dw, PSEUDO, P_DW, 0}, 104 | {NULL, "ZP", do_section, PSEUDO, P_ZP, S_ZP}, 105 | 106 | {NULL, ".BANK", do_bank, PSEUDO, P_BANK, 0}, 107 | {NULL, ".BSS", do_section, PSEUDO, P_BSS, S_BSS}, 108 | {NULL, ".BYTE", do_db, PSEUDO, P_DB, 0}, 109 | {NULL, ".CODE", do_section, PSEUDO, P_CODE, S_CODE}, 110 | {NULL, ".DATA", do_section, PSEUDO, P_DATA, S_DATA}, 111 | {NULL, ".DB", do_db, PSEUDO, P_DB, 0}, 112 | {NULL, ".DW", do_dw, PSEUDO, P_DW, 0}, 113 | {NULL, ".DS", do_ds, PSEUDO, P_DS, 0}, 114 | {NULL, ".ELSE", do_else, PSEUDO, P_ELSE, 0}, 115 | {NULL, ".ENDIF", do_endif, PSEUDO, P_ENDIF, 0}, 116 | {NULL, ".ENDM", do_endm, PSEUDO, P_ENDM, 0}, 117 | {NULL, ".ENDP", do_endp, PSEUDO, P_ENDP, P_PROC}, 118 | {NULL, ".ENDPROCGROUP",do_endp, PSEUDO, P_ENDPG, P_PGROUP}, 119 | {NULL, ".EQU", do_equ, PSEUDO, P_EQU, 0}, 120 | {NULL, ".FAIL", do_fail, PSEUDO, P_FAIL, 0}, 121 | {NULL, ".FUNC", do_func, PSEUDO, P_FUNC, 0}, 122 | {NULL, ".IF", do_if, PSEUDO, P_IF, 0}, 123 | {NULL, ".IFDEF", do_ifdef, PSEUDO, P_IFDEF, 1}, 124 | {NULL, ".IFNDEF", do_ifdef, PSEUDO, P_IFNDEF, 0}, 125 | {NULL, ".INCBIN", do_incbin, PSEUDO, P_INCBIN, 0}, 126 | {NULL, ".INCLUDE", do_include, PSEUDO, P_INCLUDE, 0}, 127 | {NULL, ".INCCHR", do_incchr, PSEUDO, P_INCCHR, 0xEA}, 128 | {NULL, ".LIST", do_list, PSEUDO, P_LIST, 0}, 129 | {NULL, ".MAC", do_macro, PSEUDO, P_MACRO, 0}, 130 | {NULL, ".MACRO", do_macro, PSEUDO, P_MACRO, 0}, 131 | {NULL, ".MLIST", do_mlist, PSEUDO, P_MLIST, 0}, 132 | {NULL, ".NOLIST", do_nolist, PSEUDO, P_NOLIST, 0}, 133 | {NULL, ".NOMLIST", do_nomlist, PSEUDO, P_NOMLIST, 0}, 134 | {NULL, ".OPT", do_opt, PSEUDO, P_OPT, 0}, 135 | {NULL, ".ORG", do_org, PSEUDO, P_ORG, 0}, 136 | {NULL, ".PAGE", do_page, PSEUDO, P_PAGE, 0}, 137 | {NULL, ".PROC", do_proc, PSEUDO, P_PROC, P_PROC}, 138 | {NULL, ".PROCGROUP", do_proc, PSEUDO, P_PGROUP, P_PGROUP}, 139 | {NULL, ".RSSET", do_rsset, PSEUDO, P_RSSET, 0}, 140 | {NULL, ".RS", do_rs, PSEUDO, P_RS, 0}, 141 | {NULL, ".WORD", do_dw, PSEUDO, P_DW, 0}, 142 | {NULL, ".ZP", do_section, PSEUDO, P_ZP, S_ZP}, 143 | {NULL, NULL, NULL, 0, 0, 0} 144 | }; 145 | 146 | -------------------------------------------------------------------------------- /nesasmsrc/macro.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "defs.h" 6 | #include "externs.h" 7 | #include "protos.h" 8 | 9 | int mopt; 10 | int in_macro; 11 | int expand_macro; 12 | char marg[8][10][80]; 13 | int midx; 14 | int mcounter, mcntmax; 15 | int mcntstack[8]; 16 | struct t_line *mstack[8]; 17 | struct t_line *mlptr; 18 | struct t_macro *macro_tbl[256]; 19 | struct t_macro *mptr; 20 | 21 | /* .macro pseudo */ 22 | 23 | void 24 | do_macro(int *ip) 25 | { 26 | if (pass == LAST_PASS) 27 | println(); 28 | else { 29 | /* error checking */ 30 | if (expand_macro) { 31 | error("Can not nest macro definitions!"); 32 | return; 33 | } 34 | if (lablptr == NULL) { 35 | /* skip spaces */ 36 | while (isspace(prlnbuf[*ip])) 37 | (*ip)++; 38 | 39 | /* search a label after the .macro */ 40 | if (colsym(ip) == 0) { 41 | error("No name for this macro!"); 42 | return; 43 | } 44 | 45 | /* put the macro name in the symbol table */ 46 | if ((lablptr = stlook(1)) == NULL) 47 | return; 48 | } 49 | if (lablptr->refcnt) { 50 | switch (lablptr->type) { 51 | case MACRO: 52 | fatal_error("Macro already defined!"); 53 | return; 54 | 55 | case FUNC: 56 | fatal_error("Symbol already used by a function!"); 57 | return; 58 | 59 | default: 60 | fatal_error("Symbol already used by a label!"); 61 | return; 62 | } 63 | } 64 | if (!check_eol(ip)) 65 | return; 66 | 67 | /* install this new macro in the hash table */ 68 | if (!macro_install()) 69 | return; 70 | } 71 | in_macro = 1; 72 | } 73 | 74 | /* .endm pseudo */ 75 | 76 | void 77 | do_endm(int *ip) 78 | { 79 | error("Unexpected ENDM!"); 80 | return; 81 | } 82 | 83 | /* search a macro in the hash table */ 84 | 85 | struct t_macro *macro_look(int *ip) 86 | { 87 | struct t_macro *ptr; 88 | char name[32]; 89 | char c; 90 | int hash; 91 | int l; 92 | 93 | /* calculate the symbol hash value and check syntax */ 94 | l = 0; 95 | hash = 0; 96 | for (;;) { 97 | c = prlnbuf[*ip]; 98 | if (c == '\0' || c == ' ' || c == '\t' || c == ';') 99 | break; 100 | if (!isalnum(c) && c != '_') 101 | return (NULL); 102 | if (l == 0) { 103 | if (isdigit(c)) 104 | return (NULL); 105 | } 106 | if (l == 31) 107 | return (NULL); 108 | name[l++] = c; 109 | hash += c; 110 | hash = (hash << 3) + (hash >> 5) + c; 111 | (*ip)++; 112 | } 113 | name[l] = '\0'; 114 | hash &= 0xFF; 115 | 116 | /* browse the hash table */ 117 | ptr = macro_tbl[hash]; 118 | while (ptr) { 119 | if (!strcmp(name, ptr->name)) 120 | break; 121 | ptr = ptr->next; 122 | } 123 | 124 | /* return result */ 125 | return (ptr); 126 | } 127 | 128 | /* extract macro arguments */ 129 | 130 | int 131 | macro_getargs(int ip) 132 | { 133 | char *ptr; 134 | char c, t; 135 | int i, j, f, arg; 136 | int level; 137 | 138 | /* can not nest too much macros */ 139 | if (midx == 7) { 140 | error("Too many nested macro calls!"); 141 | return (0); 142 | } 143 | 144 | /* initialize args */ 145 | mcntstack[midx] = mcounter; 146 | mstack[midx++] = mlptr; 147 | ptr = marg[midx][0]; 148 | arg = 0; 149 | 150 | for (i = 0; i < 9; i++) 151 | marg[midx][i][0] = '\0'; 152 | 153 | /* extract args */ 154 | for (;;) { 155 | /* skip spaces */ 156 | while (isspace(prlnbuf[ip])) 157 | ip++; 158 | 159 | c = prlnbuf[ip++]; 160 | switch (c) { 161 | /* no arg */ 162 | case ',': 163 | arg++; 164 | ptr = marg[midx][arg]; 165 | if (arg == 9) { 166 | error("Too many arguments for a macro!"); 167 | return (0); 168 | } 169 | break; 170 | 171 | /* string */ 172 | case '{': 173 | c = '}'; 174 | case '\"': 175 | i = 0; 176 | if (c == '\"') 177 | ptr[i++] = c; 178 | for (;;) { 179 | t = prlnbuf[ip++]; 180 | if (t == '\0') { 181 | error("Unterminated string!"); 182 | return (0); 183 | } 184 | if (i == 80) { 185 | error("String too long, max. 80 characters!"); 186 | return (0); 187 | } 188 | if (t == c) 189 | break; 190 | ptr[i++] = t; 191 | } 192 | if (c == '\"') 193 | ptr[i++] = t; 194 | 195 | /* skip spaces */ 196 | while (isspace(prlnbuf[ip])) 197 | ip++; 198 | 199 | /* check end of arg */ 200 | switch (prlnbuf[ip]) { 201 | case '\0': 202 | case ',': 203 | case ';': 204 | break; 205 | 206 | default: 207 | error("Syntax error!"); 208 | return (0); 209 | } 210 | 211 | /* end arg string */ 212 | ptr[i] = '\0'; 213 | break; 214 | 215 | /* end of line */ 216 | case ';': 217 | case '\0': 218 | return (1); 219 | 220 | /* continuation char */ 221 | case '\\': 222 | /* skip spaces */ 223 | i = ip; 224 | while (isspace(prlnbuf[i])) 225 | i++; 226 | 227 | /* check */ 228 | if (prlnbuf[i] == ';' || prlnbuf[i] == '\0') { 229 | /* output line */ 230 | if (pass == LAST_PASS) { 231 | println(); 232 | clearln(); 233 | } 234 | 235 | /* read a new line */ 236 | if (readline() == -1) 237 | return (0); 238 | 239 | /* rewind line pointer and continue */ 240 | ip = SFIELD; 241 | break; 242 | } 243 | 244 | /* other */ 245 | default: 246 | i = 0; 247 | j = 0; 248 | f = 0; 249 | level = 0; 250 | while (c) { 251 | if (c == ',') { 252 | if (level == 0) 253 | break; 254 | } 255 | else if ((c == '(') || (c == '[')) { 256 | level++; 257 | } 258 | else if ((c == ')') || (c == ']')) { 259 | if (level) 260 | level--; 261 | } 262 | else if (c == ';') { 263 | break; 264 | } 265 | if (f) { 266 | if (c != ' ') { 267 | while (i < j) 268 | ptr[i++] = ' '; 269 | ptr[i++] = c; 270 | f = 0; 271 | } 272 | } 273 | else if (c == ' ') { 274 | f = 1; 275 | } 276 | else { 277 | ptr[i++] = c; 278 | } 279 | if (i == 80) { 280 | error("Macro argument string too long, max. 80 characters!"); 281 | return (0); 282 | } 283 | j++; 284 | c = prlnbuf[ip++]; 285 | } 286 | ptr[i] = '\0'; 287 | ip--; 288 | 289 | /* check if arg is X or Y */ 290 | if (strlen(ptr) && arg) { 291 | c = tolower(ptr[0]); 292 | 293 | if ((c == 'x') || (c == 'y')) { 294 | if ((strcasecmp(ptr, "x++") == 0) || 295 | (strcasecmp(ptr, "y++") == 0) || 296 | (strlen(ptr) == 1)) 297 | { 298 | arg--; 299 | ptr = marg[midx][arg]; 300 | 301 | /* check string length */ 302 | if (strlen(ptr) > 75) { 303 | error("Macro argument string too long, max. 80 characters!"); 304 | return (0); 305 | } 306 | 307 | /* attach current arg to the previous one */ 308 | strcat(ptr, ","); 309 | strcat(ptr, marg[midx][arg + 1]); 310 | ptr = marg[midx][arg + 1]; 311 | ptr[0] = '\0'; 312 | } 313 | } 314 | } 315 | break; 316 | } 317 | } 318 | } 319 | 320 | /* install a macro in the hash table */ 321 | 322 | int 323 | macro_install(void) 324 | { 325 | char c; 326 | int hash = 0; 327 | int i; 328 | 329 | /* mark the macro name as reserved */ 330 | lablptr->type = MACRO; 331 | 332 | /* check macro name syntax */ 333 | if (strchr(&symbol[1], '.')) { 334 | error("Invalid macro name!"); 335 | return (0); 336 | } 337 | 338 | /* calculate symbol hash value */ 339 | for (i = 1; i <= symbol[0]; i++) { 340 | c = symbol[i]; 341 | hash += c; 342 | hash = (hash << 3) + (hash >> 5) + c; 343 | } 344 | hash &= 0xFF; 345 | 346 | /* allocate a macro struct */ 347 | mptr = (void *)malloc(sizeof(struct t_macro)); 348 | if (mptr == NULL) { 349 | error("Out of memory!"); 350 | return (0); 351 | } 352 | 353 | /* initialize it */ 354 | strcpy(mptr->name, &symbol[1]); 355 | mptr->line = NULL; 356 | mptr->next = macro_tbl[hash]; 357 | macro_tbl[hash] = mptr; 358 | mlptr = NULL; 359 | 360 | /* ok */ 361 | return (1); 362 | } 363 | 364 | /* send back the addressing mode of a macro arg */ 365 | 366 | int 367 | macro_getargtype(char *arg) 368 | { 369 | struct t_symbol *sym; 370 | char c; 371 | int i; 372 | 373 | /* skip spaces */ 374 | while (isspace(*arg)) 375 | arg++; 376 | 377 | /* get type */ 378 | switch (toupper(*arg++)) { 379 | case '\0': 380 | return (NO_ARG); 381 | 382 | case '"': 383 | return (ARG_STRING); 384 | 385 | case '#': 386 | return (ARG_IMM); 387 | 388 | case '[': 389 | return (ARG_INDIRECT); 390 | 391 | case 'A': 392 | case 'X': 393 | case 'Y': 394 | if (*arg == '\0') 395 | return (ARG_REG); 396 | 397 | default: 398 | /* symbol */ 399 | for(i = 0; i < SBOLSZ; i++) { 400 | c = arg[i]; 401 | if (isdigit(c) && (i == 0)) 402 | break; 403 | if ((!isalnum(c)) && (c != '_') && (c != '.')) 404 | break; 405 | } 406 | 407 | if (i == 0) 408 | return (ARG_ABS); 409 | else { 410 | if (c != '\0') 411 | return (ARG_ABS); 412 | else { 413 | strncpy(&symbol[1], arg, i); 414 | symbol[0] = i; 415 | symbol[i+1] = '\0'; 416 | 417 | if ((sym = stlook(0)) == NULL) 418 | return (ARG_LABEL); 419 | else { 420 | if((sym->type == UNDEF) || (sym->type == IFUNDEF)) 421 | return (ARG_LABEL); 422 | if (sym->bank == RESERVED_BANK) 423 | return (ARG_ABS); 424 | else 425 | return (ARG_LABEL); 426 | } 427 | } 428 | } 429 | } 430 | } 431 | 432 | -------------------------------------------------------------------------------- /nesasmsrc/map.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "defs.h" 5 | #include "externs.h" 6 | #include "protos.h" 7 | 8 | /* locals */ 9 | static unsigned char buffer[512]; 10 | 11 | 12 | /* ---- 13 | * pce_load_map() 14 | * ---- 15 | */ 16 | 17 | int 18 | pce_load_map(char *fname, int mode) 19 | { 20 | FILE *fp; 21 | unsigned char header[16]; 22 | int fsize; 23 | int size; 24 | int nb; 25 | int cnt; 26 | int i, j; 27 | 28 | /* init */ 29 | cnt = 0; 30 | 31 | /* open the file */ 32 | if ((fp = open_file(fname, "rb")) == NULL) { 33 | fatal_error("Can not open file!"); 34 | return (1); 35 | } 36 | 37 | /* check FMP header */ 38 | fread(header, 1, 12, fp); 39 | fsize = (header[4] << 24) + 40 | (header[5] << 16) + 41 | (header[6] << 8) + 42 | header[7] - 4; 43 | 44 | if (strncmp(header, "FORM", 4) || strncmp(&header[8], "FMAP", 4)) { 45 | /* incorrect header */ 46 | if (mode) 47 | fatal_error("Invalid FMP format!"); 48 | fclose(fp); 49 | return(mode); 50 | } 51 | 52 | /* define label */ 53 | labldef(loccnt, 1); 54 | 55 | /* output */ 56 | if (pass == LAST_PASS) 57 | loadlc(loccnt, 0); 58 | 59 | /* browse chunks */ 60 | while (fsize > 0) { 61 | fread(header, 1, 8, fp); 62 | size = (header[4] << 24) + 63 | (header[5] << 16) + 64 | (header[6] << 8) + 65 | header[7]; 66 | fsize -= 8; 67 | fsize -= size; 68 | if (fsize < 0) 69 | break; 70 | 71 | /* BODY chunk */ 72 | if (strncmp(header, "BODY", 4) == 0) { 73 | /* add size */ 74 | cnt += (size >> 1); 75 | 76 | if (pass == LAST_PASS) { 77 | /* read chunk */ 78 | while (size) { 79 | /* read a block */ 80 | nb = (size > 512) ? 512 : size; 81 | fread(buffer, 1, nb, fp); 82 | size -= nb; 83 | nb >>= 1; 84 | 85 | /* convert word -> byte */ 86 | for (i = 0, j = 0; i < nb; i++, j += 2) 87 | buffer[i] = ((buffer[j] + (buffer[j+1] << 8)) >> 5) - 1; 88 | 89 | /* output buffer */ 90 | putbuffer(buffer, nb); 91 | } 92 | } 93 | else 94 | putbuffer(NULL, size >> 1); 95 | 96 | /* ok */ 97 | break; 98 | } 99 | else { 100 | /* unsupported chunk */ 101 | fseek(fp, size, SEEK_CUR); 102 | } 103 | } 104 | 105 | /* close file */ 106 | fclose(fp); 107 | 108 | /* size */ 109 | if (lablptr) { 110 | lablptr->data_type = P_INCBIN; 111 | lablptr->data_size = cnt; 112 | } 113 | else { 114 | if (lastlabl) { 115 | if (lastlabl->data_type == P_INCBIN) 116 | lastlabl->data_size += cnt; 117 | } 118 | } 119 | 120 | /* output line */ 121 | if (pass == LAST_PASS) 122 | println(); 123 | 124 | /* ok */ 125 | return (1); 126 | } 127 | 128 | 129 | 130 | 131 | //The FMP file format 132 | //The first 12 bytes are as follows: 133 | //4bytes ASCII = 'FORM' 134 | //long int = size of file less header (which is filesize-8) 135 | //4bytes ASCII = 'FMAP' 136 | //NOTE: The chunk size long ints like the one above are stored in 137 | //'Motorola' format, NOT Intel. You will have to byteswap to get the 138 | //correct value, ie: Bytes 1,2,3,4 need to become 4,3,2,1. 139 | // 140 | //The chunks in the file follow on one after the other, and consist of 141 | //an 8byte header, and the information specific to that chunk. See 142 | //how the playback source reads in the information. The chunks can be 143 | //in any order, and some chunks may not be used in a particular file. 144 | // 145 | //Chunk header: 146 | //4bytes ASCII = ChunkID (example: 'MPHD') 147 | //long int = size of chunk data less header 148 | // 149 | //These are the chunks as of V1.1: 150 | //ATHR - Up to 4 ASCII strings of author information, separated by 0 values, 151 | // always an even size. 152 | //MPHD - Map header, see struct in mappy.c 153 | //EDHD - Editor information, see struct in mappy.c 154 | //CMAP - Colour palette for 8bit maps, red byte, green byte, 155 | // blue byte for however many colours are needed (so usually 256*3 bytes). 156 | //BKDT - Block data. Contains BLKSTR structures for however many block 157 | // structures were made. 158 | //ANDT - Animation data. Contains ANISTR structures for however many 159 | // animation structures were made, and also animation data. 160 | //BGFX - The raw graphics in whatever format the map is in. 161 | // Examples: 8bit: mapwidth*mapheight bytes per block, 162 | // in forward format *numblocks 16bit: mapwidth*mapheight*2 163 | // bytes per block, each word contains 5 bits red, 6 bits green, 164 | // 5 bits blue. 165 | //BODY - An array of short ints containing positive offsets into BKDT, 166 | // and negative offsets into ANDT. 167 | //LYR? - Where ? is an ASCII number form 1 to 7. 168 | // These are the same size and format as BODY, and allow object 169 | // layers to be used. 170 | 171 | -------------------------------------------------------------------------------- /nesasmsrc/mml.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "defs.h" 4 | #include "externs.h" 5 | #include "protos.h" 6 | 7 | /* defines */ 8 | #define SND_STOP 0 /* stop processing (track finish) */ 9 | #define SND_OFF 1 /* mute sound */ 10 | #define SND_ON 2 /* turn on sound */ 11 | #define SND_VOLUME 3 /* set voice volume (left & right) */ 12 | #define SND_FREQ 4 /* set voice frequency */ 13 | #define SND_DURATION 5 /* set voice duration */ 14 | #define SND_NOISE_FREQ 6 /* set noise frequency */ 15 | #define SND_NOISE_OFF 7 /* set noise off */ 16 | #define SND_LFO_FREQ 8 /* set LFO frequency */ 17 | #define SND_LFO_CTRL 9 /* set LFO control */ 18 | #define SND_WAVE_SINE 20 /* init to sine wave (predefined) */ 19 | #define SND_WAVE_SAW 21 /* init to sawtooth wave (predefined) */ 20 | #define SND_WAVE_SQR 22 /* init to square wave (predefined) */ 21 | #define SND_WAVE_DATA 30 /* init to inline wave data */ 22 | 23 | /* locals */ 24 | static unsigned int snd_wave; 25 | static unsigned int snd_octave; 26 | static unsigned int snd_volume; 27 | static unsigned int snd_length; 28 | static unsigned int snd_tempo; 29 | static unsigned int snd_timebase; 30 | static unsigned int snd_ticks_h, snd_ticks_l; 31 | static int snd_wave_flag; 32 | static int snd_off; 33 | static int tone_table[7] = { 10, 12, 1, 3, 5, 6, 8 }; 34 | static int freq_table[14] = { 35 | 0x001EDD, 36 | 0x0020B3, 0x0022A6, 37 | 0x0024B5, 0x0026E3, 38 | 0x002933, 39 | 0x002BA6, 0x002E40, 40 | 0x003100, 0x0033E8, 41 | 0x003700, 0x003A45, 42 | 0x003DBA, 43 | 0x004166 44 | }; 45 | 46 | /* protos */ 47 | int mml_get_value(char **ptr); 48 | int mml_get_length(char **ptr); 49 | int mml_calc_duration(unsigned int len); 50 | 51 | 52 | /* ---- 53 | * mml_start() 54 | * ---- 55 | */ 56 | 57 | int 58 | mml_start(unsigned char *buffer) 59 | { 60 | *buffer = SND_OFF; 61 | 62 | snd_off = 1; 63 | snd_wave_flag = 0; 64 | snd_octave = 4; 65 | snd_volume = 15; 66 | snd_length = 4; 67 | snd_tempo = 128; 68 | snd_timebase = 60; 69 | snd_ticks_h = 0; 70 | snd_ticks_l = 0; 71 | 72 | /* ok */ 73 | return (1); 74 | } 75 | 76 | 77 | /* ---- 78 | * mml_stop() 79 | * ---- 80 | */ 81 | 82 | int 83 | mml_stop(unsigned char *buffer) 84 | { 85 | *buffer = SND_STOP; 86 | 87 | return (1); 88 | } 89 | 90 | 91 | /* ---- 92 | * mml_parse() 93 | * ---- 94 | */ 95 | 96 | int 97 | mml_parse(unsigned char *buffer, int bufsize, char *ptr) 98 | { 99 | unsigned int tone, freq, value, len; 100 | int size = 0; 101 | char c; 102 | 103 | /* parse string */ 104 | while ((c = *ptr++) != '\0') { 105 | /* check buffer size */ 106 | if (bufsize < 7) { 107 | fatal_error("Internal error: MML buffer too small!"); 108 | return (-1); 109 | } 110 | 111 | switch (c) { 112 | /* octave */ 113 | case 'O': 114 | snd_octave = mml_get_value(&ptr); 115 | 116 | if ((snd_octave < 1) || (snd_octave > 7)) { 117 | error("Incorrect octave!"); 118 | return (-1); 119 | } 120 | break; 121 | 122 | /* volume */ 123 | case 'V': 124 | snd_volume = mml_get_value(&ptr); 125 | 126 | if (snd_volume > 15) { 127 | error("Incorrect volume!"); 128 | return (-1); 129 | } 130 | 131 | /* gen code */ 132 | *buffer++ = SND_VOLUME; 133 | *buffer++ = (snd_volume << 4) + snd_volume; 134 | size += 2; 135 | break; 136 | 137 | /* tempo */ 138 | case 'T': 139 | snd_tempo = mml_get_value(&ptr); 140 | 141 | if ((snd_tempo < 32) || (snd_tempo > 256)) { 142 | error("Incorrect tempo!"); 143 | return (-1); 144 | } 145 | break; 146 | 147 | /* length */ 148 | case 'L': 149 | snd_length = mml_get_length(&ptr); 150 | 151 | if (!snd_length) { 152 | error("Incorrect note length!"); 153 | return (-1); 154 | } 155 | break; 156 | 157 | /* notes */ 158 | case 'A': 159 | case 'B': 160 | case 'C': 161 | case 'D': 162 | case 'E': 163 | case 'F': 164 | case 'G': 165 | /* base */ 166 | tone = tone_table[c - 'A']; 167 | 168 | /* extra commands */ 169 | if ((*ptr == '#') || (*ptr == '+')) { 170 | tone++; 171 | ptr++; 172 | } 173 | else if (*ptr == '-') { 174 | tone--; 175 | ptr++; 176 | } 177 | if (isdigit(*ptr)) 178 | len = (mml_get_length(&ptr) << 8); 179 | else { 180 | len = (snd_length << 8); 181 | } 182 | if (*ptr == '.') { 183 | len = (len * 0xC0) >> 8; 184 | ptr++; 185 | } 186 | 187 | /* check length */ 188 | if (!len) { 189 | error("Incorrect note length!"); 190 | return (-1); 191 | } 192 | 193 | /* calculate frequency */ 194 | freq = (freq_table[tone] << (snd_octave - 1)); 195 | value = (((3580000 * 16) / freq) + 1) >> 1; 196 | 197 | /* gen code */ 198 | *buffer++ = SND_FREQ; 199 | *buffer++ = (value) & 0xFF; 200 | *buffer++ = (value >> 8) & 0xFF; 201 | 202 | if (snd_wave_flag) { 203 | /* new waveform */ 204 | snd_wave_flag = 0; 205 | snd_off = 0; 206 | *buffer++ = SND_WAVE_SINE + (snd_wave - 1); 207 | size += 1; 208 | } 209 | else { 210 | if (snd_off) { 211 | /* sound on */ 212 | snd_off = 0; 213 | *buffer++ = SND_ON; 214 | size += 1; 215 | } 216 | } 217 | 218 | *buffer++ = SND_DURATION; 219 | *buffer++ = mml_calc_duration(len); 220 | size += 5; 221 | break; 222 | 223 | /* rest */ 224 | case 'R': 225 | /* local length */ 226 | if (isdigit(*ptr)) 227 | len = (mml_get_length(&ptr) << 8); 228 | else { 229 | len = (0x0400); 230 | } 231 | if (*ptr == '.') { 232 | len = (len * 0xC0) >> 8; 233 | ptr++; 234 | } 235 | 236 | /* check length */ 237 | if (!len) { 238 | error("Incorrect note length!"); 239 | return (-1); 240 | } 241 | 242 | /* gen code */ 243 | *buffer++ = SND_OFF; 244 | *buffer++ = SND_DURATION; 245 | *buffer++ = mml_calc_duration(len); 246 | snd_off = 1; 247 | size += 3; 248 | break; 249 | 250 | /* waveform */ 251 | case 'W': 252 | snd_wave = mml_get_value(&ptr); 253 | snd_wave_flag = 1; 254 | 255 | if ((snd_wave < 1) || (snd_wave > 3)) { 256 | error("Incorrect waveform!"); 257 | return (-1); 258 | } 259 | break; 260 | 261 | /* other */ 262 | default: 263 | error("Syntax error!"); 264 | return (-1); 265 | } 266 | 267 | /* update size */ 268 | bufsize -= size; 269 | } 270 | 271 | /* ok */ 272 | return (size); 273 | } 274 | 275 | 276 | /* ---- 277 | * mml_get_value() 278 | * ---- 279 | */ 280 | 281 | int 282 | mml_get_value(char **ptr) 283 | { 284 | unsigned int value; 285 | char c; 286 | 287 | /* get value */ 288 | value = 0; 289 | 290 | for (;;) { 291 | c = **ptr; 292 | 293 | if (!isdigit(c)) 294 | break; 295 | if (value > 65535) 296 | return (-1); 297 | 298 | value = (value * 10) + (c - '0'); 299 | (*ptr)++; 300 | } 301 | 302 | /* ok */ 303 | return (value); 304 | } 305 | 306 | 307 | /* ---- 308 | * mml_get_length() 309 | * ---- 310 | */ 311 | 312 | int 313 | mml_get_length(char **ptr) 314 | { 315 | int len; 316 | 317 | len = mml_get_value(ptr); 318 | 319 | switch (len) { 320 | case 1: 321 | case 2: 322 | case 3: 323 | case 4: 324 | case 6: 325 | case 8: 326 | case 12: 327 | case 16: 328 | case 24: 329 | case 32: 330 | case 48: 331 | case 64: 332 | case 96: 333 | return (len); 334 | 335 | default: 336 | return (0); 337 | } 338 | } 339 | 340 | 341 | /* ---- 342 | * mml_calc_duration() 343 | * ---- 344 | */ 345 | 346 | int 347 | mml_calc_duration(unsigned int len) 348 | { 349 | unsigned int ticks, mask, tmp; 350 | 351 | /* ticks */ 352 | ticks = 0xC00000 / len; 353 | 354 | /* base */ 355 | if (snd_timebase == 0) { 356 | /* timer */ 357 | mask = 0xFF; 358 | snd_ticks_h = (ticks >> 8); 359 | snd_ticks_l = (ticks & 0xFF) + snd_ticks_l; 360 | } 361 | else { 362 | /* fixed frequency (ie. vsync) */ 363 | mask = 0xFFFFFF; 364 | tmp = (256 - snd_tempo) * snd_timebase * ticks * 8; 365 | snd_ticks_h = (tmp >> 24); 366 | snd_ticks_l = (tmp & 0xFFFFFF) + snd_ticks_l; 367 | } 368 | 369 | /* adjust timings */ 370 | if (snd_ticks_l > mask) { 371 | snd_ticks_l &= mask; 372 | snd_ticks_h++; 373 | } 374 | if (snd_ticks_h == 0) 375 | snd_ticks_h = 1; 376 | 377 | /* result */ 378 | return (snd_ticks_h - 1); 379 | } 380 | 381 | -------------------------------------------------------------------------------- /nesasmsrc/nes.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "defs.h" 4 | #include "externs.h" 5 | #include "protos.h" 6 | #include "nes.h" 7 | 8 | /* locals */ 9 | static int ines_prg; /* number of prg banks */ 10 | static int ines_chr; /* number of character banks */ 11 | static int ines_mapper[2]; /* rom mapper type */ 12 | static struct INES { /* INES rom header */ 13 | unsigned char id[4]; 14 | unsigned char prg; 15 | unsigned char chr; 16 | unsigned char mapper[2]; 17 | unsigned char unused[8]; 18 | } header; 19 | 20 | 21 | /* ---- 22 | * write_header() 23 | * ---- 24 | * generate and write rom header 25 | */ 26 | 27 | void 28 | nes_write_header(FILE *f, int banks) 29 | { 30 | /* setup INES header */ 31 | memset(&header, 0, sizeof(header)); 32 | header.id[0] = 'N'; 33 | header.id[1] = 'E'; 34 | header.id[2] = 'S'; 35 | header.id[3] = 26; 36 | header.prg = ines_prg; 37 | header.chr = ines_chr; 38 | header.mapper[0] = ines_mapper[0]; 39 | header.mapper[1] = ines_mapper[1]; 40 | 41 | /* write */ 42 | fwrite(&header, sizeof(header), 1, f); 43 | } 44 | 45 | 46 | /* ---- 47 | * pack_8x8_tile() 48 | * ---- 49 | * encode a 8x8 tile for the NES 50 | */ 51 | 52 | int 53 | nes_pack_8x8_tile(unsigned char *buffer, void *data, int line_offset, int format) 54 | { 55 | int i, j; 56 | int cnt, err; 57 | unsigned int pixel; 58 | unsigned char *ptr; 59 | unsigned int *packed; 60 | 61 | /* pack the tile only in the last pass */ 62 | if (pass != LAST_PASS) 63 | return (16); 64 | 65 | /* clear buffer */ 66 | memset(buffer, 0, 16); 67 | 68 | /* encode the tile */ 69 | switch (format) { 70 | case CHUNKY_TILE: 71 | /* 8-bit chunky format */ 72 | cnt = 0; 73 | ptr = data; 74 | 75 | for (i = 0; i < 8; i++) { 76 | for (j = 0; j < 8; j++) { 77 | pixel = ptr[j ^ 0x07]; 78 | buffer[cnt] |= (pixel & 0x01) ? (1 << j) : 0; 79 | buffer[cnt+8] |= (pixel & 0x02) ? (1 << j) : 0; 80 | } 81 | ptr += line_offset; 82 | cnt += 1; 83 | } 84 | break; 85 | 86 | case PACKED_TILE: 87 | /* 4-bit packed format */ 88 | cnt = 0; 89 | err = 0; 90 | packed = data; 91 | 92 | for (i = 0; i < 8; i++) { 93 | pixel = packed[i]; 94 | 95 | for (j = 0; j < 8; j++) { 96 | /* check for errors */ 97 | if (pixel & 0x0C) 98 | err++; 99 | 100 | /* convert the tile */ 101 | buffer[cnt] |= (pixel & 0x01) ? (1 << j) : 0; 102 | buffer[cnt+8] |= (pixel & 0x02) ? (1 << j) : 0; 103 | pixel >>= 4; 104 | } 105 | cnt += 1; 106 | } 107 | 108 | /* error message */ 109 | if (err) 110 | error("Incorrect pixel color index!"); 111 | break; 112 | 113 | default: 114 | /* other formats not supported */ 115 | error("Internal error: unsupported format passed to 'pack_8x8_tile'!"); 116 | break; 117 | } 118 | 119 | /* ok */ 120 | return (16); 121 | } 122 | 123 | 124 | /* ---- 125 | * do_defchr() 126 | * ---- 127 | * .defchr pseudo 128 | */ 129 | 130 | void 131 | nes_defchr(int *ip) 132 | { 133 | unsigned char buffer[16]; 134 | unsigned int data[8]; 135 | int size; 136 | int i; 137 | 138 | /* define label */ 139 | labldef(loccnt, 1); 140 | 141 | /* output infos */ 142 | data_loccnt = loccnt; 143 | data_size = 3; 144 | data_level = 3; 145 | 146 | /* get tile data */ 147 | for (i = 0; i < 8; i++) { 148 | /* get value */ 149 | if (!evaluate(ip, (i < 7) ? ',' : ';')) 150 | return; 151 | 152 | /* store value */ 153 | data[i] = value; 154 | } 155 | 156 | /* encode tile */ 157 | size = nes_pack_8x8_tile(buffer, data, 0, PACKED_TILE); 158 | 159 | /* store tile */ 160 | putbuffer(buffer, size); 161 | 162 | /* output line */ 163 | if (pass == LAST_PASS) 164 | println(); 165 | } 166 | 167 | 168 | /* ---- 169 | * do_inesprg() 170 | * ---- 171 | * .inesprg pseudo 172 | */ 173 | 174 | void 175 | nes_inesprg(int *ip) 176 | { 177 | if (!evaluate(ip, ';')) 178 | return; 179 | 180 | if ((value < 0) || (value > 64)) 181 | { 182 | error("PRG bank value out of range!"); 183 | 184 | return; 185 | } 186 | 187 | ines_prg = value; 188 | 189 | if (pass == LAST_PASS) 190 | { 191 | println(); 192 | } 193 | } 194 | 195 | 196 | /* ---- 197 | * do_ineschr() 198 | * ---- 199 | * .ineschr pseudo 200 | */ 201 | 202 | void 203 | nes_ineschr(int *ip) 204 | { 205 | if (!evaluate(ip, ';')) 206 | return; 207 | 208 | if ((value < 0) || (value > 64)) 209 | { 210 | error("CHR bank value out of range!"); 211 | 212 | return; 213 | } 214 | 215 | ines_chr = value; 216 | 217 | if (pass == LAST_PASS) 218 | { 219 | println(); 220 | } 221 | } 222 | 223 | 224 | /* ---- 225 | * do_inesmap() 226 | * ---- 227 | * .inesmap pseudo 228 | */ 229 | 230 | void 231 | nes_inesmap(int *ip) 232 | { 233 | if (!evaluate(ip, ';')) 234 | return; 235 | 236 | if ((value < 0) || (value > 255)) 237 | { 238 | error("Mapper value out of range!"); 239 | 240 | return; 241 | } 242 | 243 | ines_mapper[0] &= 0x0F; 244 | ines_mapper[0] |= (value & 0x0F) << 4; 245 | ines_mapper[1] = (value & 0xF0); 246 | 247 | if (pass == LAST_PASS) 248 | { 249 | println(); 250 | } 251 | } 252 | 253 | 254 | /* ---- 255 | * do_inesmir() 256 | * ---- 257 | * .ines.mirror pseudo 258 | */ 259 | 260 | void 261 | nes_inesmir(int *ip) 262 | { 263 | if (!evaluate(ip, ';')) 264 | return; 265 | 266 | if ((value < 0) || (value > 15)) 267 | { 268 | error("Mirror value out of range!"); 269 | 270 | return; 271 | } 272 | 273 | ines_mapper[0] &= 0xF0; 274 | ines_mapper[0] |= (value & 0x0F); 275 | 276 | if (pass == LAST_PASS) 277 | { 278 | println(); 279 | } 280 | } 281 | 282 | -------------------------------------------------------------------------------- /nesasmsrc/nes.h: -------------------------------------------------------------------------------- 1 | 2 | /* NES.C */ 3 | void nes_write_header(FILE *f, int banks); 4 | int nes_pack_8x8_tile(unsigned char *buffer, void *data, int line_offset, int format); 5 | void nes_defchr(int *ip); 6 | void nes_inesprg(int *ip); 7 | void nes_ineschr(int *ip); 8 | void nes_inesmap(int *ip); 9 | void nes_inesmir(int *ip); 10 | 11 | /* NES specific pseudos */ 12 | struct t_opcode nes_pseudo[11] = { 13 | {NULL, "DEFCHR", nes_defchr, PSEUDO, P_DEFCHR, 0}, 14 | {NULL, "INESPRG", nes_inesprg, PSEUDO, P_INESPRG, 0}, 15 | {NULL, "INESCHR", nes_ineschr, PSEUDO, P_INESCHR, 0}, 16 | {NULL, "INESMAP", nes_inesmap, PSEUDO, P_INESMAP, 0}, 17 | {NULL, "INESMIR", nes_inesmir, PSEUDO, P_INESMIR, 0}, 18 | 19 | {NULL, ".DEFCHR", nes_defchr, PSEUDO, P_DEFCHR, 0}, 20 | {NULL, ".INESPRG", nes_inesprg, PSEUDO, P_INESPRG, 0}, 21 | {NULL, ".INESCHR", nes_ineschr, PSEUDO, P_INESCHR, 0}, 22 | {NULL, ".INESMAP", nes_inesmap, PSEUDO, P_INESMAP, 0}, 23 | {NULL, ".INESMIR", nes_inesmir, PSEUDO, P_INESMIR, 0}, 24 | {NULL, NULL, NULL, 0, 0, 0} 25 | }; 26 | 27 | /* NES machine description */ 28 | struct t_machine nes = { 29 | MACHINE_NES, /* type */ 30 | "NESASM", /* asm_name */ 31 | "NES Assembler (v3.1)", /* asm_title */ 32 | ".nes", /* rom_ext */ 33 | "NES_INCLUDE", /* include_env */ 34 | 0x100, /* zp_limit */ 35 | 0x800, /* ram_limit */ 36 | 0, /* ram_base */ 37 | 0, /* ram_page */ 38 | RESERVED_BANK, /* ram_bank */ 39 | NULL, /* inst */ 40 | nes_pseudo, /* pseudo_inst */ 41 | nes_pack_8x8_tile, /* pack_8x8_tile */ 42 | NULL, /* pack_16x16_tile */ 43 | NULL, /* pack_16x16_sprite */ 44 | nes_write_header /* write_header */ 45 | }; 46 | 47 | -------------------------------------------------------------------------------- /nesasmsrc/output.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "defs.h" 4 | #include "externs.h" 5 | #include "protos.h" 6 | 7 | 8 | /* ---- 9 | * println() 10 | * ---- 11 | * prints the contents of prlnbuf 12 | */ 13 | 14 | void 15 | println(void) 16 | { 17 | int nb, cnt; 18 | int i; 19 | 20 | /* check if output possible */ 21 | if (list_level == 0) 22 | return; 23 | if (!xlist || !asm_opt[OPT_LIST] || (expand_macro && !asm_opt[OPT_MACRO])) 24 | return; 25 | 26 | /* update line buffer if necessary */ 27 | if (continued_line) 28 | strcpy(prlnbuf, tmplnbuf); 29 | 30 | /* output */ 31 | if (data_loccnt == -1) 32 | /* line buffer */ 33 | fprintf(lst_fp, "%s\n", prlnbuf); 34 | else { 35 | /* line buffer + data bytes */ 36 | loadlc(data_loccnt, 0); 37 | 38 | /* number of bytes */ 39 | nb = loccnt - data_loccnt; 40 | 41 | /* check level */ 42 | if ((data_level > list_level) && (nb > 3)) 43 | /* doesn't match */ 44 | fprintf(lst_fp, "%s\n", prlnbuf); 45 | else { 46 | /* ok */ 47 | cnt = 0; 48 | for (i = 0; i < nb; i++) { 49 | if (bank >= RESERVED_BANK) { 50 | prlnbuf[16 + (3*cnt)] = '-'; 51 | prlnbuf[17 + (3*cnt)] = '-'; 52 | } 53 | else { 54 | hexcon(2, rom[bank][data_loccnt]); 55 | prlnbuf[16 + (3*cnt)] = hex[1]; 56 | prlnbuf[17 + (3*cnt)] = hex[2]; 57 | } 58 | data_loccnt++; 59 | cnt++; 60 | if (cnt == data_size) { 61 | cnt = 0; 62 | fprintf(lst_fp, "%s\n", prlnbuf); 63 | clearln(); 64 | loadlc(data_loccnt, 0); 65 | } 66 | } 67 | if (cnt) 68 | fprintf(lst_fp, "%s\n", prlnbuf); 69 | } 70 | } 71 | } 72 | 73 | 74 | /* ---- 75 | * clearln() 76 | * ---- 77 | * clear prlnbuf 78 | */ 79 | 80 | void 81 | clearln(void) 82 | { 83 | int i; 84 | 85 | for (i = 0; i < SFIELD; i++) 86 | prlnbuf[i] = ' '; 87 | prlnbuf[i] = 0; 88 | } 89 | 90 | 91 | /* ---- 92 | * loadlc() 93 | * ---- 94 | * load 16 bit value in printable form into prlnbuf 95 | */ 96 | 97 | void 98 | loadlc(int offset, int pos) 99 | { 100 | int i; 101 | 102 | if (pos) 103 | i = 16; 104 | else 105 | i = 7; 106 | 107 | if (pos == 0) { 108 | if (bank >= RESERVED_BANK) { 109 | prlnbuf[i++] = '-'; 110 | prlnbuf[i++] = '-'; 111 | } 112 | else { 113 | hexcon(2, bank); 114 | prlnbuf[i++] = hex[1]; 115 | prlnbuf[i++] = hex[2]; 116 | } 117 | prlnbuf[i++] = ':'; 118 | offset += page << XXX_BANK_SHIFT; 119 | } 120 | hexcon(4, offset); 121 | prlnbuf[i++] = hex[1]; 122 | prlnbuf[i++] = hex[2]; 123 | prlnbuf[i++] = hex[3]; 124 | prlnbuf[i] = hex[4]; 125 | } 126 | 127 | 128 | /* ---- 129 | * hexcon() 130 | * ---- 131 | * convert number supplied as argument to hexadecimal in hex[digit] 132 | */ 133 | 134 | void 135 | hexcon(int digit, int num) 136 | { 137 | for (; digit > 0; digit--) { 138 | hex[digit] = (num & 0x0f) + '0'; 139 | if (hex[digit] > '9') 140 | hex[digit] += 'A' - '9' - 1; 141 | num >>= 4; 142 | } 143 | } 144 | 145 | 146 | /* ---- 147 | * putbyte() 148 | * ---- 149 | * store a byte in the rom 150 | */ 151 | 152 | void 153 | putbyte(int offset, int data) 154 | { 155 | if (bank >= RESERVED_BANK) 156 | return; 157 | if (offset < XXX_BANK_SIZE) { 158 | rom[bank][offset] = (data) & 0xFF; 159 | map[bank][offset] = section + (page << 5); 160 | 161 | /* update rom size */ 162 | if (bank > max_bank) 163 | max_bank = bank; 164 | } 165 | } 166 | 167 | 168 | /* ---- 169 | * putword() 170 | * ---- 171 | * store a word in the rom 172 | */ 173 | 174 | void 175 | putword(int offset, int data) 176 | { 177 | if (bank >= RESERVED_BANK) 178 | return; 179 | if (offset < XXX_BANK_MASK) { 180 | /* low byte */ 181 | rom[bank][offset] = (data) & 0xFF; 182 | map[bank][offset] = section + (page << 5); 183 | 184 | /* high byte */ 185 | rom[bank][offset+1] = (data >> 8) & 0xFF; 186 | map[bank][offset+1] = section + (page << 5); 187 | 188 | /* update rom size */ 189 | if (bank > max_bank) 190 | max_bank = bank; 191 | } 192 | } 193 | 194 | 195 | /* ---- 196 | * putbuffer() 197 | * ---- 198 | * copy a buffer at the current location 199 | */ 200 | 201 | void 202 | putbuffer(void *data, int size) 203 | { 204 | int addr; 205 | 206 | /* check size */ 207 | if (size == 0) 208 | return; 209 | 210 | /* check if the buffer will fit in the rom */ 211 | if (bank >= RESERVED_BANK) { 212 | addr = loccnt + size; 213 | 214 | if (addr > XXX_BANK_MASK) { 215 | fatal_error("PROC overflow!"); 216 | return; 217 | } 218 | } 219 | else { 220 | addr = loccnt + size + (bank << XXX_BANK_SHIFT); 221 | 222 | if (addr > rom_limit) { 223 | fatal_error("ROM overflow!"); 224 | return; 225 | } 226 | 227 | /* copy the buffer */ 228 | if (pass == LAST_PASS) { 229 | if (data) { 230 | memcpy(&rom[bank][loccnt], data, size); 231 | memset(&map[bank][loccnt], section + (page << 5), size); 232 | } 233 | else { 234 | memset(&rom[bank][loccnt], 0, size); 235 | memset(&map[bank][loccnt], section + (page << 5), size); 236 | } 237 | } 238 | } 239 | 240 | /* update the location counter */ 241 | bank += (loccnt + size) >> XXX_BANK_SHIFT; 242 | loccnt = (loccnt + size) & XXX_BANK_MASK; 243 | 244 | /* update rom size */ 245 | if (bank < RESERVED_BANK) { 246 | if (bank > max_bank) { 247 | if (loccnt) 248 | max_bank = bank; 249 | else 250 | max_bank = bank - 1; 251 | } 252 | } 253 | } 254 | 255 | 256 | /* ---- 257 | * write_srec() 258 | * ---- 259 | */ 260 | 261 | void 262 | write_srec(char *file, char *ext, int base) 263 | { 264 | unsigned char data, chksum; 265 | char fname[128]; 266 | int addr, dump, cnt, pos, i, j; 267 | FILE *fp; 268 | 269 | /* status message */ 270 | if (!strcmp(ext, "mx")) 271 | printf("writing mx file... "); 272 | else 273 | printf("writing s-record file... "); 274 | 275 | /* flush output */ 276 | fflush(stdout); 277 | 278 | /* add the file extension */ 279 | strcpy(fname, file); 280 | strcat(fname, "."); 281 | strcat(fname, ext); 282 | 283 | /* open the file */ 284 | if ((fp = fopen(fname, "w")) == NULL) { 285 | printf("can not open file '%s'!\n", fname); 286 | return; 287 | } 288 | 289 | /* dump the rom */ 290 | dump = 0; 291 | cnt = 0; 292 | pos = 0; 293 | 294 | for (i = 0; i <= max_bank; i++) { 295 | for (j = 0; j < XXX_BANK_SIZE; j++) { 296 | if (map[i][j] != 0xFF) { 297 | /* data byte */ 298 | if (cnt == 0) 299 | pos = j; 300 | cnt++; 301 | if (cnt == 32) 302 | dump = 1; 303 | } 304 | else { 305 | /* free byte */ 306 | if (cnt) 307 | dump = 1; 308 | } 309 | if (j == (XXX_BANK_SIZE-1)) 310 | if (cnt) 311 | dump = 1; 312 | 313 | /* dump */ 314 | if (dump) { 315 | dump = 0; 316 | addr = base + (i << XXX_BANK_SHIFT) + pos; 317 | chksum = cnt + ((addr >> 16) & 0xFF) + 318 | ((addr >> 8) & 0xFF) + 319 | ((addr) & 0xFF) + 320 | 4; 321 | 322 | /* number, address */ 323 | fprintf(fp, "S2%02X%06X", cnt + 4, addr); 324 | 325 | /* code */ 326 | while (cnt) { 327 | data = rom[i][pos++]; 328 | chksum += data; 329 | fprintf(fp, "%02X", data); 330 | cnt--; 331 | } 332 | 333 | /* chksum */ 334 | fprintf(fp, "%02X\n", (~chksum) & 0xFF); 335 | } 336 | } 337 | } 338 | 339 | /* starting address */ 340 | addr = ((map[0][0] >> 5) << XXX_BANK_SHIFT); 341 | chksum = ((addr >> 8) & 0xFF) + (addr & 0xFF) + 4; 342 | fprintf(fp, "S804%06X%02X", addr, (~chksum) & 0xFF); 343 | 344 | /* ok */ 345 | fclose(fp); 346 | printf("OK\n"); 347 | } 348 | 349 | 350 | /* ---- 351 | * fatal_error() 352 | * ---- 353 | * stop compilation 354 | */ 355 | 356 | void 357 | fatal_error(char *stptr) 358 | { 359 | error(stptr); 360 | stop_pass = 1; 361 | } 362 | 363 | 364 | /* ---- 365 | * error() 366 | * ---- 367 | * error printing routine 368 | */ 369 | 370 | void 371 | error(char *stptr) 372 | { 373 | warning(stptr); 374 | errcnt++; 375 | } 376 | 377 | 378 | /* ---- 379 | * warning() 380 | * ---- 381 | * warning printing routine 382 | */ 383 | 384 | void 385 | warning(char *stptr) 386 | { 387 | int i, temp; 388 | 389 | /* put the source line number into prlnbuf */ 390 | i = 4; 391 | temp = slnum; 392 | while (temp != 0) { 393 | prlnbuf[i--] = temp % 10 + '0'; 394 | temp /= 10; 395 | } 396 | 397 | /* update the current file name */ 398 | if (infile_error != infile_num) { 399 | infile_error = infile_num; 400 | printf("#[%i] %s\n", infile_num, input_file[infile_num].name); 401 | } 402 | 403 | /* output the line and the error message */ 404 | loadlc(loccnt, 0); 405 | printf("%s\n", prlnbuf); 406 | printf(" %s\n", stptr); 407 | } 408 | 409 | -------------------------------------------------------------------------------- /nesasmsrc/pce.h: -------------------------------------------------------------------------------- 1 | 2 | /* PCE.C */ 3 | void pce_write_header(FILE *f, int banks); 4 | int pce_pack_8x8_tile(unsigned char *buffer, void *data, int line_offset, int format); 5 | int pce_pack_16x16_tile(unsigned char *buffer, void *data, int line_offset, int format); 6 | int pce_pack_16x16_sprite(unsigned char *buffer, void *data, int line_offset, int format); 7 | void pce_defchr(int *ip); 8 | void pce_defpal(int *ip); 9 | void pce_defspr(int *ip); 10 | void pce_incbat(int *ip); 11 | void pce_incpal(int *ip); 12 | void pce_incspr(int *ip); 13 | void pce_inctile(int *ip); 14 | void pce_incmap(int *ip); 15 | void pce_vram(int *ip); 16 | void pce_pal(int *ip); 17 | void pce_develo(int *ip); 18 | void pce_mml(int *ip); 19 | 20 | /* MML.C */ 21 | int mml_start(unsigned char *buffer); 22 | int mml_stop(unsigned char *buffer); 23 | int mml_parse(unsigned char *buffer, int bufsize, char *ptr); 24 | 25 | /* PCE specific instructions */ 26 | struct t_opcode pce_inst[82] = { 27 | {NULL, "BBR", class10,0, 0x0F, 0}, 28 | {NULL, "BBR0", class5, 0, 0x0F, 0}, 29 | {NULL, "BBR1", class5, 0, 0x1F, 0}, 30 | {NULL, "BBR2", class5, 0, 0x2F, 0}, 31 | {NULL, "BBR3", class5, 0, 0x3F, 0}, 32 | {NULL, "BBR4", class5, 0, 0x4F, 0}, 33 | {NULL, "BBR5", class5, 0, 0x5F, 0}, 34 | {NULL, "BBR6", class5, 0, 0x6F, 0}, 35 | {NULL, "BBR7", class5, 0, 0x7F, 0}, 36 | {NULL, "BBS", class10,0, 0x8F, 0}, 37 | {NULL, "BBS0", class5, 0, 0x8F, 0}, 38 | {NULL, "BBS1", class5, 0, 0x9F, 0}, 39 | {NULL, "BBS2", class5, 0, 0xAF, 0}, 40 | {NULL, "BBS3", class5, 0, 0xBF, 0}, 41 | {NULL, "BBS4", class5, 0, 0xCF, 0}, 42 | {NULL, "BBS5", class5, 0, 0xDF, 0}, 43 | {NULL, "BBS6", class5, 0, 0xEF, 0}, 44 | {NULL, "BBS7", class5, 0, 0xFF, 0}, 45 | {NULL, "BRA", class2, 0, 0x80, 0}, 46 | {NULL, "BSR", class2, 0, 0x44, 0}, 47 | {NULL, "CLA", class1, 0, 0x62, 0}, 48 | {NULL, "CLX", class1, 0, 0x82, 0}, 49 | {NULL, "CLY", class1, 0, 0xC2, 0}, 50 | {NULL, "CSH", class1, 0, 0xD4, 0}, 51 | {NULL, "CSL", class1, 0, 0x54, 0}, 52 | {NULL, "PHX", class1, 0, 0xDA, 0}, 53 | {NULL, "PHY", class1, 0, 0x5A, 0}, 54 | {NULL, "PLX", class1, 0, 0xFA, 0}, 55 | {NULL, "PLY", class1, 0, 0x7A, 0}, 56 | {NULL, "RMB", class9, 0, 0x07, 0}, 57 | {NULL, "RMB0", class4, ZP, 0x03, 0}, 58 | {NULL, "RMB1", class4, ZP, 0x13, 0}, 59 | {NULL, "RMB2", class4, ZP, 0x23, 0}, 60 | {NULL, "RMB3", class4, ZP, 0x33, 0}, 61 | {NULL, "RMB4", class4, ZP, 0x43, 0}, 62 | {NULL, "RMB5", class4, ZP, 0x53, 0}, 63 | {NULL, "RMB6", class4, ZP, 0x63, 0}, 64 | {NULL, "RMB7", class4, ZP, 0x73, 0}, 65 | {NULL, "SAX", class1, 0, 0x22, 0}, 66 | {NULL, "SAY", class1, 0, 0x42, 0}, 67 | {NULL, "SET", class1, 0, 0xF4, 0}, 68 | {NULL, "SMB", class9, 0, 0x87, 0}, 69 | {NULL, "SMB0", class4, ZP, 0x83, 0}, 70 | {NULL, "SMB1", class4, ZP, 0x93, 0}, 71 | {NULL, "SMB2", class4, ZP, 0xA3, 0}, 72 | {NULL, "SMB3", class4, ZP, 0xB3, 0}, 73 | {NULL, "SMB4", class4, ZP, 0xC3, 0}, 74 | {NULL, "SMB5", class4, ZP, 0xD3, 0}, 75 | {NULL, "SMB6", class4, ZP, 0xE3, 0}, 76 | {NULL, "SMB7", class4, ZP, 0xF3, 0}, 77 | {NULL, "ST0", class4, IMM, 0x03, 1}, 78 | {NULL, "ST1", class4, IMM, 0x13, 1}, 79 | {NULL, "ST2", class4, IMM, 0x23, 1}, 80 | {NULL, "STZ", class4, ZP|ZP_X|ABS|ABS_X, 0x00, 0x05}, 81 | {NULL, "SXY", class1, 0, 0x02, 0}, 82 | {NULL, "TAI", class6, 0, 0xF3, 0}, 83 | {NULL, "TAM", class8, 0, 0x53, 0}, 84 | {NULL, "TAM0", class3, 0, 0x53, 0x01}, 85 | {NULL, "TAM1", class3, 0, 0x53, 0x02}, 86 | {NULL, "TAM2", class3, 0, 0x53, 0x04}, 87 | {NULL, "TAM3", class3, 0, 0x53, 0x08}, 88 | {NULL, "TAM4", class3, 0, 0x53, 0x10}, 89 | {NULL, "TAM5", class3, 0, 0x53, 0x20}, 90 | {NULL, "TAM6", class3, 0, 0x53, 0x40}, 91 | {NULL, "TAM7", class3, 0, 0x53, 0x80}, 92 | {NULL, "TDD", class6, 0, 0xC3, 0}, 93 | {NULL, "TIA", class6, 0, 0xE3, 0}, 94 | {NULL, "TII", class6, 0, 0x73, 0}, 95 | {NULL, "TIN", class6, 0, 0xD3, 0}, 96 | {NULL, "TMA", class8, 0, 0x43, 0}, 97 | {NULL, "TMA0", class3, 0, 0x43, 0x01}, 98 | {NULL, "TMA1", class3, 0, 0x43, 0x02}, 99 | {NULL, "TMA2", class3, 0, 0x43, 0x04}, 100 | {NULL, "TMA3", class3, 0, 0x43, 0x08}, 101 | {NULL, "TMA4", class3, 0, 0x43, 0x10}, 102 | {NULL, "TMA5", class3, 0, 0x43, 0x20}, 103 | {NULL, "TMA6", class3, 0, 0x43, 0x40}, 104 | {NULL, "TMA7", class3, 0, 0x43, 0x80}, 105 | {NULL, "TRB", class4, ZP|ABS, 0x10, 0}, 106 | {NULL, "TSB", class4, ZP|ABS, 0x00, 0}, 107 | {NULL, "TST", class7, 0, 0x00, 0}, 108 | {NULL, NULL, NULL, 0, 0, 0} 109 | }; 110 | 111 | /* PCE specific pseudos */ 112 | struct t_opcode pce_pseudo[23] = { 113 | {NULL, "DEFCHR", pce_defchr, PSEUDO, P_DEFCHR, 0}, 114 | {NULL, "DEFPAL", pce_defpal, PSEUDO, P_DEFPAL, 0}, 115 | {NULL, "DEFSPR", pce_defspr, PSEUDO, P_DEFSPR, 0}, 116 | {NULL, "INCBAT", pce_incbat, PSEUDO, P_INCBAT, 0xD5}, 117 | {NULL, "INCSPR", pce_incspr, PSEUDO, P_INCSPR, 0xEA}, 118 | {NULL, "INCPAL", pce_incpal, PSEUDO, P_INCPAL, 0xF8}, 119 | {NULL, "INCTILE",pce_inctile,PSEUDO, P_INCTILE,0xEA}, 120 | {NULL, "INCMAP", pce_incmap, PSEUDO, P_INCMAP, 0xD5}, 121 | {NULL, "MML", pce_mml, PSEUDO, P_MML, 0}, 122 | {NULL, "PAL", pce_pal, PSEUDO, P_PAL, 0}, 123 | {NULL, "VRAM", pce_vram, PSEUDO, P_VRAM, 0}, 124 | 125 | {NULL, ".DEFCHR", pce_defchr, PSEUDO, P_DEFCHR, 0}, 126 | {NULL, ".DEFPAL", pce_defpal, PSEUDO, P_DEFPAL, 0}, 127 | {NULL, ".DEFSPR", pce_defspr, PSEUDO, P_DEFSPR, 0}, 128 | {NULL, ".INCBAT", pce_incbat, PSEUDO, P_INCBAT, 0xD5}, 129 | {NULL, ".INCSPR", pce_incspr, PSEUDO, P_INCSPR, 0xEA}, 130 | {NULL, ".INCPAL", pce_incpal, PSEUDO, P_INCPAL, 0xF8}, 131 | {NULL, ".INCTILE",pce_inctile,PSEUDO, P_INCTILE,0xEA}, 132 | {NULL, ".INCMAP", pce_incmap, PSEUDO, P_INCMAP, 0xD5}, 133 | {NULL, ".MML", pce_mml, PSEUDO, P_MML, 0}, 134 | {NULL, ".PAL", pce_pal, PSEUDO, P_PAL, 0}, 135 | {NULL, ".VRAM", pce_vram, PSEUDO, P_VRAM, 0}, 136 | {NULL, NULL, NULL, 0, 0, 0} 137 | }; 138 | 139 | /* PCE machine description */ 140 | struct t_machine pce = { 141 | MACHINE_PCE, /* type */ 142 | "PCEAS", /* asm_name */ 143 | "PC-Engine Assembler (v2.51)", /* asm_title */ 144 | ".pce", /* rom_ext */ 145 | "PCE_INCLUDE", /* include_env */ 146 | 0xD8, /* zp_limit */ 147 | XXX_BANK_SIZE, /* ram_limit */ 148 | XXX_BANK_SIZE, /* ram_base */ 149 | 1, /* ram_page */ 150 | 0xF8, /* ram_bank */ 151 | pce_inst, /* inst */ 152 | pce_pseudo, /* pseudo_inst */ 153 | pce_pack_8x8_tile, /* pack_8x8_tile */ 154 | pce_pack_16x16_tile, /* pack_16x16_tile */ 155 | pce_pack_16x16_sprite, /* pack_16x16_sprite */ 156 | pce_write_header /* write_header */ 157 | }; 158 | 159 | -------------------------------------------------------------------------------- /nesasmsrc/proc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "defs.h" 6 | #include "externs.h" 7 | #include "protos.h" 8 | 9 | struct t_proc *proc_tbl[256]; 10 | struct t_proc *proc_ptr; 11 | struct t_proc *proc_first; 12 | struct t_proc *proc_last; 13 | int proc_nb; 14 | int call_ptr; 15 | int call_bank; 16 | 17 | /* protos */ 18 | struct t_proc *proc_look(void); 19 | int proc_install(void); 20 | void poke(int addr, int data); 21 | 22 | 23 | /* ---- 24 | * do_call() 25 | * ---- 26 | * call pseudo 27 | */ 28 | 29 | void 30 | do_call(int *ip) 31 | { 32 | struct t_proc *ptr; 33 | int value; 34 | 35 | /* define label */ 36 | labldef(loccnt, 1); 37 | 38 | /* update location counter */ 39 | data_loccnt = loccnt; 40 | loccnt += 3; 41 | 42 | /* generate code */ 43 | if (pass == LAST_PASS) { 44 | /* skip spaces */ 45 | while (isspace(prlnbuf[*ip])) 46 | (*ip)++; 47 | 48 | /* extract name */ 49 | if (!colsym(ip)) { 50 | if (symbol[0] == 0) 51 | fatal_error("Syntax error!"); 52 | return; 53 | } 54 | 55 | /* check end of line */ 56 | check_eol(ip); 57 | 58 | /* lookup proc table */ 59 | if((ptr = proc_look())) { 60 | /* check banks */ 61 | if (bank == ptr->bank) 62 | value = ptr->org + 0xA000; 63 | else { 64 | /* different */ 65 | if (ptr->call) 66 | value = ptr->call; 67 | else { 68 | /* new call */ 69 | value = call_ptr + 0x8000; 70 | ptr->call = value; 71 | 72 | /* init */ 73 | if (call_ptr == 0) 74 | call_bank = ++max_bank; 75 | 76 | /* install */ 77 | poke(call_ptr++, 0xA8); // tay 78 | poke(call_ptr++, 0x43); // tma #5 79 | poke(call_ptr++, 0x20); 80 | poke(call_ptr++, 0x48); // pha 81 | poke(call_ptr++, 0xA9); // lda #... 82 | poke(call_ptr++, ptr->bank); 83 | poke(call_ptr++, 0x53); // tam #5 84 | poke(call_ptr++, 0x20); 85 | poke(call_ptr++, 0x98); // tya 86 | poke(call_ptr++, 0x20); // jsr ... 87 | poke(call_ptr++, (ptr->org & 0xFF)); 88 | poke(call_ptr++, (ptr->org >> 8) + 0xA0); 89 | poke(call_ptr++, 0xA8); // tay 90 | poke(call_ptr++, 0x68); // pla 91 | poke(call_ptr++, 0x53); // tam #5 92 | poke(call_ptr++, 0x20); 93 | poke(call_ptr++, 0x98); // tya 94 | poke(call_ptr++, 0x60); // rts 95 | } 96 | } 97 | } 98 | else { 99 | /* lookup symbol table */ 100 | if ((lablptr = stlook(0)) == NULL) { 101 | fatal_error("Undefined destination!"); 102 | return; 103 | } 104 | 105 | /* get symbol value */ 106 | value = lablptr->value; 107 | } 108 | 109 | /* opcode */ 110 | putbyte(data_loccnt, 0x20); 111 | putword(data_loccnt+1, value); 112 | 113 | /* output line */ 114 | println(); 115 | } 116 | } 117 | 118 | 119 | /* ---- 120 | * do_proc() 121 | * ---- 122 | * .proc pseudo 123 | */ 124 | 125 | void 126 | do_proc(int *ip) 127 | { 128 | struct t_proc *ptr; 129 | 130 | /* check if nesting procs/groups */ 131 | if (proc_ptr) { 132 | if (optype == P_PGROUP) { 133 | fatal_error("Can not declare a group inside a proc/group!"); 134 | return; 135 | } 136 | else { 137 | if (proc_ptr->type == P_PROC) { 138 | fatal_error("Can not nest procs!"); 139 | return; 140 | } 141 | } 142 | } 143 | 144 | /* get proc name */ 145 | if (lablptr) { 146 | strcpy(&symbol[1], &lablptr->name[1]); 147 | symbol[0] = strlen(&symbol[1]); 148 | } 149 | else { 150 | /* skip spaces */ 151 | while (isspace(prlnbuf[*ip])) 152 | (*ip)++; 153 | 154 | /* extract name */ 155 | if (!colsym(ip)) { 156 | if (symbol[0]) 157 | return; 158 | if (optype == P_PROC) { 159 | fatal_error("Proc name is missing!"); 160 | return; 161 | } 162 | 163 | /* default name */ 164 | sprintf(&symbol[1], "__group_%i__", proc_nb + 1); 165 | symbol[0] = strlen(&symbol[1]); 166 | } 167 | 168 | /* lookup symbol table */ 169 | if ((lablptr = stlook(1)) == NULL) 170 | return; 171 | } 172 | 173 | /* check symbol */ 174 | if (symbol[1] == '.') { 175 | fatal_error("Proc/group name can not be local!"); 176 | return; 177 | } 178 | 179 | /* check end of line */ 180 | if (!check_eol(ip)) 181 | return; 182 | 183 | /* search (or create new) proc */ 184 | if((ptr = proc_look())) 185 | proc_ptr = ptr; 186 | else { 187 | if (!proc_install()) 188 | return; 189 | } 190 | if (proc_ptr->refcnt) { 191 | fatal_error("Proc/group multiply defined!"); 192 | return; 193 | } 194 | 195 | /* incrememte proc ref counter */ 196 | proc_ptr->refcnt++; 197 | 198 | /* backup current bank infos */ 199 | bank_glabl[section][bank] = glablptr; 200 | bank_loccnt[section][bank] = loccnt; 201 | bank_page[section][bank] = page; 202 | proc_ptr->old_bank = bank; 203 | proc_nb++; 204 | 205 | /* set new bank infos */ 206 | bank = proc_ptr->bank; 207 | page = 5; 208 | loccnt = proc_ptr->org; 209 | glablptr = lablptr; 210 | 211 | /* define label */ 212 | labldef(loccnt, 1); 213 | 214 | /* output */ 215 | if (pass == LAST_PASS) { 216 | loadlc((page << XXX_BANK_SHIFT) + loccnt, 0); 217 | println(); 218 | } 219 | } 220 | 221 | 222 | /* ---- 223 | * do_endp() 224 | * ---- 225 | * .endp pseudo 226 | */ 227 | 228 | void 229 | do_endp(int *ip) 230 | { 231 | if (proc_ptr == NULL) { 232 | fatal_error("Unexpected ENDP/ENDPROCGROUP!"); 233 | return; 234 | } 235 | if (optype != proc_ptr->type) { 236 | fatal_error("Unexpected ENDP/ENDPROCGROUP!"); 237 | return; 238 | } 239 | 240 | /* check end of line */ 241 | if (!check_eol(ip)) 242 | return; 243 | 244 | /* record proc size */ 245 | bank = proc_ptr->old_bank; 246 | proc_ptr->size = loccnt - proc_ptr->base; 247 | proc_ptr = proc_ptr->group; 248 | 249 | /* restore previous bank settings */ 250 | if (proc_ptr == NULL) { 251 | page = bank_page[section][bank]; 252 | loccnt = bank_loccnt[section][bank]; 253 | glablptr = bank_glabl[section][bank]; 254 | } 255 | 256 | /* output */ 257 | if (pass == LAST_PASS) 258 | println(); 259 | } 260 | 261 | 262 | /* ---- 263 | * proc_reloc() 264 | * ---- 265 | * 266 | */ 267 | 268 | void 269 | proc_reloc(void) 270 | { 271 | struct t_symbol *sym; 272 | struct t_symbol *local; 273 | struct t_proc *group; 274 | int i; 275 | int addr; 276 | int tmp; 277 | 278 | if (proc_nb == 0) 279 | return; 280 | 281 | /* init */ 282 | proc_ptr = proc_first; 283 | bank = max_bank + 1; 284 | addr = 0; 285 | 286 | /* alloc memory */ 287 | while (proc_ptr) { 288 | /* proc */ 289 | if (proc_ptr->group == NULL) { 290 | tmp = addr + proc_ptr->size; 291 | 292 | /* bank change */ 293 | if (tmp > XXX_BANK_SIZE) { 294 | printf("Wtf is this...?\n"); 295 | bank++; 296 | addr = 0; 297 | } 298 | if (bank > bank_limit) { 299 | fatal_error("Not enough ROM space for procs!"); 300 | return; 301 | } 302 | 303 | /* reloc proc */ 304 | proc_ptr->bank = bank; 305 | proc_ptr->org = addr; 306 | addr += proc_ptr->size; 307 | } 308 | 309 | /* group */ 310 | else { 311 | /* reloc proc */ 312 | group = proc_ptr->group; 313 | proc_ptr->bank = bank; 314 | proc_ptr->org += (group->org - group->base); 315 | } 316 | 317 | /* next */ 318 | max_bank = bank; 319 | proc_ptr->refcnt = 0; 320 | proc_ptr = proc_ptr->link; 321 | } 322 | 323 | /* remap proc symbols */ 324 | for (i = 0; i < 256; i++) { 325 | sym = hash_tbl[i]; 326 | 327 | while (sym) { 328 | proc_ptr = sym->proc; 329 | 330 | /* remap addr */ 331 | if (sym->proc) { 332 | sym->bank = proc_ptr->bank; 333 | sym->value += (proc_ptr->org - proc_ptr->base); 334 | 335 | /* local symbols */ 336 | if (sym->local) { 337 | local = sym->local; 338 | 339 | while (local) { 340 | proc_ptr = local->proc; 341 | 342 | /* remap addr */ 343 | if (local->proc) { 344 | local->bank = proc_ptr->bank; 345 | local->value += (proc_ptr->org - proc_ptr->base); 346 | } 347 | 348 | /* next */ 349 | local = local->next; 350 | } 351 | } 352 | } 353 | 354 | /* next */ 355 | sym = sym->next; 356 | } 357 | } 358 | 359 | /* reserve call bank */ 360 | lablset("_call_bank", max_bank + 1); 361 | 362 | /* reset */ 363 | proc_ptr = NULL; 364 | proc_nb = 0; 365 | } 366 | 367 | 368 | /* ---- 369 | * proc_look() 370 | * ---- 371 | * 372 | */ 373 | 374 | struct t_proc * 375 | proc_look(void) 376 | { 377 | struct t_proc *ptr; 378 | int hash; 379 | 380 | /* search the procedure in the hash table */ 381 | hash = symhash(); 382 | ptr = proc_tbl[hash]; 383 | while (ptr) { 384 | if (!strcmp(&symbol[1], ptr->name)) 385 | break; 386 | ptr = ptr->next; 387 | } 388 | 389 | /* ok */ 390 | return (ptr); 391 | } 392 | 393 | 394 | /* ---- 395 | * proc_install() 396 | * ---- 397 | * install a procedure in the hash table 398 | * 399 | */ 400 | 401 | int 402 | proc_install(void) 403 | { 404 | struct t_proc *ptr; 405 | int hash; 406 | 407 | /* allocate a new proc struct */ 408 | if ((ptr = (void *)malloc(sizeof(struct t_proc))) == NULL) { 409 | error("Out of memory!"); 410 | return (0); 411 | } 412 | 413 | /* initialize it */ 414 | strcpy(ptr->name, &symbol[1]); 415 | hash = symhash(); 416 | ptr->bank = (optype == P_PGROUP) ? GROUP_BANK : PROC_BANK; 417 | ptr->base = proc_ptr ? loccnt : 0; 418 | ptr->org = ptr->base; 419 | ptr->size = 0; 420 | ptr->call = 0; 421 | ptr->refcnt = 0; 422 | ptr->link = NULL; 423 | ptr->next = proc_tbl[hash]; 424 | ptr->group = proc_ptr; 425 | ptr->type = optype; 426 | proc_ptr = ptr; 427 | proc_tbl[hash] = proc_ptr; 428 | 429 | /* link it */ 430 | if (proc_first == NULL) { 431 | proc_first = proc_ptr; 432 | proc_last = proc_ptr; 433 | } 434 | else { 435 | proc_last->link = proc_ptr; 436 | proc_last = proc_ptr; 437 | } 438 | 439 | /* ok */ 440 | return (1); 441 | } 442 | 443 | 444 | /* ---- 445 | * poke() 446 | * ---- 447 | * 448 | */ 449 | 450 | void 451 | poke(int addr, int data) 452 | { 453 | rom[call_bank][addr] = data; 454 | map[call_bank][addr] = S_CODE + (4 << 5); 455 | } 456 | 457 | -------------------------------------------------------------------------------- /nesasmsrc/protos.h: -------------------------------------------------------------------------------- 1 | 2 | /* ASSEMBLE.C */ 3 | void assemble(void); 4 | int oplook(int *idx); 5 | void addinst(struct t_opcode *optbl); 6 | int check_eol(int *ip); 7 | void do_if(int *ip); 8 | void do_else(int *ip); 9 | void do_endif(int *ip); 10 | void do_ifdef(int *ip); 11 | 12 | /* CODE.C */ 13 | void class1(int *ip); 14 | void class2(int *ip); 15 | void class3(int *ip); 16 | void class4(int *ip); 17 | void class5(int *ip); 18 | void class6(int *ip); 19 | void class7(int *ip); 20 | void class8(int *ip); 21 | void class9(int *ip); 22 | void class10(int *ip); 23 | int getoperand(int *ip, int flag, int last_char); 24 | int getstring(int *ip, char *buffer, int size); 25 | 26 | /* COMMAND.C */ 27 | void do_pseudo(int *ip); 28 | void do_list(int *ip); 29 | void do_mlist(int *ip); 30 | void do_nolist(int *ip); 31 | void do_nomlist(int *ip); 32 | void do_db(int *ip); 33 | void do_dw(int *ip); 34 | void do_equ(int *ip); 35 | void do_page(int *ip); 36 | void do_org(int *ip); 37 | void do_bank(int *ip); 38 | void do_incbin(int *ip); 39 | void do_mx(char *fname); 40 | void do_include(int *ip); 41 | void do_rsset(int *ip); 42 | void do_rs(int *ip); 43 | void do_ds(int *ip); 44 | void do_fail(int *ip); 45 | void do_section(int *ip); 46 | void do_incchr(int *ip); 47 | void do_opt(int *ip); 48 | int htoi(char *str, int nb); 49 | 50 | /* CRC.C */ 51 | void crc_init(void); 52 | unsigned int crc_calc(unsigned char *data, int len); 53 | 54 | /* EXPR.C */ 55 | int evaluate(int *ip, char flag); 56 | int push_val(int type); 57 | int getsym(void); 58 | int check_keyword(void); 59 | int push_op(int op); 60 | int do_op(void); 61 | int check_func_args(char *func_name); 62 | 63 | /* FUNC.C */ 64 | void do_func(int *ip); 65 | int func_look(void); 66 | int func_install(int ip); 67 | int func_extract(int ip); 68 | int func_getargs(void); 69 | 70 | /* INPUT.C */ 71 | void init_path(void); 72 | int readline(void); 73 | int open_input(char *name); 74 | int close_input(void); 75 | FILE *open_file(char *fname, char *mode); 76 | 77 | /* MACRO.C */ 78 | void do_macro(int *ip); 79 | void do_endm(int *ip); 80 | struct t_macro *macro_look(int *ip); 81 | int macro_getargs(int ip); 82 | int macro_install(void); 83 | int macro_getargtype(char *arg); 84 | 85 | /* MAIN.C */ 86 | int main(int argc, char **argv); 87 | int calc_bank_base(void); 88 | void help(void); 89 | void show_seg_usage(void); 90 | 91 | /* MAP.C */ 92 | int pce_load_map(char *fname, int mode); 93 | 94 | /* OUTPUT.C */ 95 | void println(void); 96 | void clearln(void); 97 | void loadlc(int offset, int f); 98 | void hexcon(int digit, int num); 99 | void putbyte(int offset, int data); 100 | void putword(int offset, int data); 101 | void putbuffer(void *data, int size); 102 | void write_srec(char *fname, char *ext, int base); 103 | void error(char *stptr); 104 | void warning(char *stptr); 105 | void fatal_error(char *stptr); 106 | 107 | /* PCX.C */ 108 | int pcx_pack_8x8_tile(unsigned char *buffer, int x, int y); 109 | int pcx_pack_16x16_tile(unsigned char *buffer, int x, int y); 110 | int pcx_pack_16x16_sprite(unsigned char *buffer, int x, int y); 111 | int pcx_set_tile(struct t_symbol *ref, unsigned int offset); 112 | int pcx_search_tile(unsigned char *data, int size); 113 | int pcx_get_args(int *ip); 114 | int pcx_parse_args(int i, int nb, int *a, int *b, int *c, int *d, int size); 115 | int pcx_load(char *name); 116 | void decode_256(FILE *fp, int w, int h); 117 | void decode_16(FILE *fp, int w, int h); 118 | 119 | /* PROC.C */ 120 | void do_call(int *ip); 121 | void do_proc(int *ip); 122 | void do_endp(int *ip); 123 | void proc_reloc(void); 124 | 125 | /* SYMBOL.C */ 126 | int symhash(void); 127 | int colsym(int *ip); 128 | struct t_symbol *stlook(int flag); 129 | struct t_symbol *stinstall(int hash, int type); 130 | int labldef(int lval, int flag); 131 | void lablset(char *name, int val); 132 | void lablremap(void); 133 | void funcdump(const char *name, const char *in_fname); 134 | 135 | -------------------------------------------------------------------------------- /nesasmsrc/symbol.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "defs.h" 6 | #include "externs.h" 7 | #include "protos.h" 8 | 9 | 10 | /* ---- 11 | * symhash() 12 | * ---- 13 | * calculate the hash value of a symbol 14 | */ 15 | 16 | int 17 | symhash(void) 18 | { 19 | int i; 20 | char c; 21 | int hash = 0; 22 | 23 | /* hash value */ 24 | for (i = 1; i <= symbol[0]; i++) { 25 | c = symbol[i]; 26 | hash += c; 27 | hash = (hash << 3) + (hash >> 5) + c; 28 | } 29 | 30 | /* ok */ 31 | return (hash & 0xFF); 32 | } 33 | 34 | 35 | /* ---- 36 | * colsym() 37 | * ---- 38 | * collect a symbol from prlnbuf into symbol[], 39 | * leaves prlnbuf pointer at first invalid symbol character, 40 | * returns 0 if no symbol collected 41 | */ 42 | 43 | int 44 | colsym(int *ip) 45 | { 46 | int err = 0; 47 | int i = 0; 48 | char c; 49 | 50 | /* get the symbol */ 51 | for (;;) { 52 | c = prlnbuf[*ip]; 53 | if (isdigit(c) && (i == 0)) 54 | break; 55 | if ((!isalnum(c)) && (c != '_') && (c != '.')) 56 | break; 57 | if (i < (SBOLSZ - 1)) 58 | symbol[++i] = c; 59 | (*ip)++; 60 | } 61 | 62 | symbol[0] = i; 63 | symbol[i+1] = '\0'; 64 | 65 | /* check if it's a reserved symbol */ 66 | if (i == 1) { 67 | switch (toupper(symbol[1])) { 68 | case 'A': 69 | case 'X': 70 | case 'Y': 71 | err = 1; 72 | break; 73 | } 74 | } 75 | if (check_keyword()) 76 | err = 1; 77 | 78 | /* error */ 79 | if (err) { 80 | fatal_error("Reserved symbol!"); 81 | // symbol[0] = 0; 82 | // symbol[1] = '\0'; 83 | return (0); 84 | } 85 | 86 | /* ok */ 87 | return (i); 88 | } 89 | 90 | 91 | /* ---- 92 | * stlook() 93 | * ---- 94 | * symbol table lookup 95 | * if found, return pointer to symbol 96 | * else, install symbol as undefined and return pointer 97 | */ 98 | 99 | struct t_symbol *stlook(int flag) 100 | { 101 | struct t_symbol *sym; 102 | int sym_flag = 0; 103 | int hash; 104 | 105 | /* local symbol */ 106 | if (symbol[1] == '.') { 107 | if (glablptr) { 108 | /* search the symbol in the local list */ 109 | sym = glablptr->local; 110 | 111 | while (sym) { 112 | if (!strcmp(symbol, sym->name)) 113 | break; 114 | sym = sym->next; 115 | } 116 | 117 | /* new symbol */ 118 | if (sym == NULL) { 119 | if (flag) { 120 | sym = stinstall(0, 1); 121 | sym_flag = 1; 122 | } 123 | } 124 | } 125 | else { 126 | error("Local symbol not allowed here!"); 127 | return (NULL); 128 | } 129 | } 130 | 131 | /* global symbol */ 132 | else { 133 | /* search symbol */ 134 | hash = symhash(); 135 | sym = hash_tbl[hash]; 136 | while (sym) { 137 | if (!strcmp(symbol, sym->name)) 138 | break; 139 | sym = sym->next; 140 | } 141 | 142 | /* new symbol */ 143 | if (sym == NULL) { 144 | if (flag) { 145 | sym = stinstall(hash, 0); 146 | sym_flag = 1; 147 | } 148 | } 149 | } 150 | 151 | /* incremente symbol reference counter */ 152 | if (sym_flag == 0) { 153 | if (sym) 154 | sym->refcnt++; 155 | } 156 | 157 | /* ok */ 158 | return (sym); 159 | } 160 | 161 | 162 | /* ---- 163 | * stinstall() 164 | * ---- 165 | * install symbol into symbol hash table 166 | */ 167 | 168 | struct t_symbol *stinstall(int hash, int type) 169 | { 170 | struct t_symbol *sym; 171 | 172 | /* allocate symbol structure */ 173 | if ((sym = (void *)malloc(sizeof(struct t_symbol))) == NULL) { 174 | fatal_error("Out of memory!"); 175 | return (NULL); 176 | } 177 | 178 | /* init the symbol struct */ 179 | sym->type = if_expr ? IFUNDEF : UNDEF; 180 | sym->value = 0; 181 | sym->local = NULL; 182 | sym->proc = NULL; 183 | sym->bank = RESERVED_BANK; 184 | sym->nb = 0; 185 | sym->size = 0; 186 | sym->page = -1; 187 | sym->vram = -1; 188 | sym->pal = -1; 189 | sym->refcnt = 0; 190 | sym->reserved = 0; 191 | sym->data_type = -1; 192 | sym->data_size = 0; 193 | strcpy(sym->name, symbol); 194 | 195 | /* add the symbol to the hash table */ 196 | if (type) { 197 | /* local */ 198 | sym->next = glablptr->local; 199 | glablptr->local = sym; 200 | } 201 | else { 202 | /* global */ 203 | sym->next = hash_tbl[hash]; 204 | hash_tbl[hash] = sym; 205 | } 206 | 207 | /* ok */ 208 | return (sym); 209 | } 210 | 211 | 212 | /* ---- 213 | * labldef() 214 | * ---- 215 | * assign to label pointed to by lablptr, 216 | * checking for valid definition, etc. 217 | */ 218 | 219 | int 220 | labldef(int lval, int flag) 221 | { 222 | char c; 223 | 224 | /* check for NULL ptr */ 225 | if (lablptr == NULL) 226 | return (0); 227 | 228 | /* adjust symbol address */ 229 | if (flag) 230 | lval = (lval & XXX_BANK_MASK) | (page << XXX_BANK_SHIFT); 231 | 232 | /* first pass */ 233 | if (pass == FIRST_PASS) { 234 | switch (lablptr->type) { 235 | /* undefined */ 236 | case UNDEF: 237 | lablptr->type = DEFABS; 238 | lablptr->value = lval; 239 | break; 240 | 241 | /* already defined - error */ 242 | case IFUNDEF: 243 | error("Can not define this label, declared as undefined in an IF expression!"); 244 | return (-1); 245 | 246 | case MACRO: 247 | error("Symbol already used by a macro!"); 248 | return (-1); 249 | 250 | case FUNC: 251 | error("Symbol already used by a function!"); 252 | return (-1); 253 | 254 | default: 255 | /* reserved label */ 256 | if (lablptr->reserved) { 257 | fatal_error("Reserved symbol!"); 258 | return (-1); 259 | } 260 | 261 | /* compare the values */ 262 | if (lablptr->value == lval) 263 | break; 264 | 265 | /* normal label */ 266 | lablptr->type = MDEF; 267 | lablptr->value = 0; 268 | error("Label multiply defined!"); 269 | return (-1); 270 | } 271 | } 272 | 273 | /* second pass */ 274 | else { 275 | if ((lablptr->value != lval) || 276 | ((flag) && (bank < bank_limit) && (lablptr->bank != bank_base + bank))) 277 | { 278 | fatal_error("Internal error[1]!"); 279 | return (-1); 280 | } 281 | } 282 | 283 | /* update symbol data */ 284 | if (flag) { 285 | if (section == S_CODE) 286 | lablptr->proc = proc_ptr; 287 | lablptr->bank = bank_base + bank; 288 | lablptr->page = page; 289 | 290 | /* check if it's a local or global symbol */ 291 | c = lablptr->name[1]; 292 | if (c == '.') 293 | /* local */ 294 | lastlabl = NULL; 295 | else { 296 | /* global */ 297 | glablptr = lablptr; 298 | lastlabl = lablptr; 299 | } 300 | } 301 | 302 | /* ok */ 303 | return (0); 304 | } 305 | 306 | 307 | /* ---- 308 | * lablset() 309 | * ---- 310 | * create/update a reserved symbol 311 | */ 312 | 313 | void 314 | lablset(char *name, int val) 315 | { 316 | int len; 317 | 318 | len = strlen(name); 319 | lablptr = NULL; 320 | 321 | if (len) { 322 | symbol[0] = len; 323 | strcpy(&symbol[1], name); 324 | lablptr = stlook(1); 325 | 326 | if (lablptr) { 327 | lablptr->type = DEFABS; 328 | lablptr->value = val; 329 | lablptr->reserved = 1; 330 | } 331 | } 332 | 333 | /* ok */ 334 | return; 335 | } 336 | 337 | 338 | /* ---- 339 | * lablremap() 340 | * ---- 341 | * remap all the labels 342 | */ 343 | 344 | void 345 | lablremap(void) 346 | { 347 | struct t_symbol *sym; 348 | int i; 349 | 350 | /* browse the symbol table */ 351 | for (i = 0; i < 256; i++) { 352 | sym = hash_tbl[i]; 353 | while (sym) { 354 | /* remap the bank */ 355 | if (sym->bank <= bank_limit) 356 | sym->bank += bank_base; 357 | sym = sym->next; 358 | } 359 | } 360 | } 361 | 362 | 363 | void funcdump(const char *name, const char *in_fname) 364 | { 365 | int i; 366 | FILE *fns; 367 | 368 | fns = fopen(name, "w"); 369 | if (!fns) { 370 | printf("Cannot open function file '%s'!\n", name); 371 | exit(1); 372 | } 373 | 374 | fprintf(fns, "; %s\n", in_fname); 375 | 376 | for (i = 0; i < 256; i++) { 377 | struct t_symbol *sym; 378 | for (sym = hash_tbl[i]; sym; sym = sym->next) { 379 | if (sym->name && sym->bank < RESERVED_BANK) { 380 | fprintf(fns, "%-32s = $%04X\n", sym->name+1, sym->value); 381 | } 382 | } 383 | } 384 | 385 | fclose(fns); 386 | } 387 | -------------------------------------------------------------------------------- /nesasmsrc/vars.h: -------------------------------------------------------------------------------- 1 | unsigned char rom[128][XXX_BANK_SIZE]; 2 | unsigned char map[128][XXX_BANK_SIZE]; 3 | char bank_name[128][64]; 4 | int bank_loccnt[4][256]; 5 | int bank_page[4][256]; 6 | int max_zp; /* higher used address in zero page */ 7 | int max_bss; /* higher used address in ram */ 8 | int max_bank; /* last bank used */ 9 | int data_loccnt; /* data location counter */ 10 | int data_size; /* size of binary output (in bytes) */ 11 | int data_level; /* data output level, must be <= listlevel to be outputed */ 12 | int loccnt; /* location counter */ 13 | int bank; /* current bank */ 14 | int bank_base; /* bank base index */ 15 | int rom_limit; /* bank limit */ 16 | int bank_limit; /* rom max. size in bytes */ 17 | int page; /* page */ 18 | int rsbase; /* .rs counter */ 19 | int section; /* current section: S_ZP, S_BSS, S_CODE or S_DATA */ 20 | int section_bank[4]; /* current bank for each section */ 21 | int stop_pass; /* stop the program; set by fatal_error() */ 22 | int errcnt; /* error counter */ 23 | struct t_machine *machine; 24 | struct t_opcode *inst_tbl[256]; /* instructions hash table */ 25 | struct t_symbol *hash_tbl[256]; /* label hash table */ 26 | struct t_symbol *lablptr; /* label pointer into symbol table */ 27 | struct t_symbol *glablptr; /* pointer to the latest defined global label */ 28 | struct t_symbol *lastlabl; /* last label we have seen */ 29 | struct t_symbol *bank_glabl[4][256]; /* latest global symbol for each bank */ 30 | char hex[5]; /* hexadecimal character buffer */ 31 | void (*opproc)(int *); /* instruction gen proc */ 32 | int opflg; /* instruction flags */ 33 | int opval; /* instruction value */ 34 | int optype; /* instruction type */ 35 | char opext; /* instruction extension (.l or .h) */ 36 | int pass; /* pass counter */ 37 | char prlnbuf[LAST_CH_POS+4]; /* input line buffer */ 38 | char tmplnbuf[LAST_CH_POS+4]; /* temporary line buffer */ 39 | int slnum; /* source line number counter */ 40 | char symbol[SBOLSZ+1]; /* temporary symbol storage */ 41 | int undef; /* undefined symbol in expression flg */ 42 | unsigned int value; /* operand field value */ 43 | int opvaltab[6][16] = { 44 | {0x08, 0x08, 0x04, 0x14, 0x14, 0x11, 0x00, 0x10, // CPX CPY LDX LDY 45 | 0x0C, 0x1C, 0x18, 0x2C, 0x3C, 0x00, 0x00, 0x00}, 46 | {0x00, 0x00, 0x04, 0x14, 0x14, 0x00, 0x00, 0x00, // ST0 ST1 ST2 TAM TMA 47 | 0x0C, 0x1C, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00}, 48 | {0x00, 0x89, 0x24, 0x34, 0x00, 0x00, 0x00, 0x00, // BIT 49 | 0x2C, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 50 | {0x3A, 0x00, 0xC6, 0xD6, 0x00, 0x00, 0x00, 0x00, // DEC 51 | 0xCE, 0xDE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 52 | {0x1A, 0x00, 0xE6, 0xF6, 0x00, 0x00, 0x00, 0x00, // INC 53 | 0xEE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 54 | {0x00, 0x00, 0x64, 0x74, 0x00, 0x00, 0x00, 0x00, // STZ 55 | 0x9C, 0x9E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} 56 | }; 57 | 58 | -------------------------------------------------------------------------------- /nesasmsrc/vs/nesasm-vs.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31702.278 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nesasm-vs", "nesasm-vs.vcxproj", "{1D84F35D-B482-4371-99B4-05E921F65B20}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {1D84F35D-B482-4371-99B4-05E921F65B20}.Debug|x64.ActiveCfg = Debug|x64 17 | {1D84F35D-B482-4371-99B4-05E921F65B20}.Debug|x64.Build.0 = Debug|x64 18 | {1D84F35D-B482-4371-99B4-05E921F65B20}.Debug|x86.ActiveCfg = Debug|Win32 19 | {1D84F35D-B482-4371-99B4-05E921F65B20}.Debug|x86.Build.0 = Debug|Win32 20 | {1D84F35D-B482-4371-99B4-05E921F65B20}.Release|x64.ActiveCfg = Release|x64 21 | {1D84F35D-B482-4371-99B4-05E921F65B20}.Release|x64.Build.0 = Release|x64 22 | {1D84F35D-B482-4371-99B4-05E921F65B20}.Release|x86.ActiveCfg = Release|Win32 23 | {1D84F35D-B482-4371-99B4-05E921F65B20}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {447CDC86-EA4E-4197-87ED-B36E35A75AE5} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /nesasmsrc/vs/nesasm-vs.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {1d84f35d-b482-4371-99b4-05e921f65b20} 25 | nesasmvs 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v142 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v142 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v142 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v142 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | false 78 | 79 | 80 | true 81 | 82 | 83 | false 84 | 85 | 86 | 87 | Level3 88 | true 89 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 90 | true 91 | 92 | 93 | Console 94 | true 95 | 96 | 97 | 98 | 99 | Level3 100 | true 101 | true 102 | true 103 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 104 | true 105 | 106 | 107 | Console 108 | true 109 | true 110 | true 111 | 112 | 113 | 114 | 115 | Level3 116 | true 117 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 118 | true 119 | 120 | 121 | Console 122 | true 123 | 124 | 125 | 126 | 127 | Level3 128 | true 129 | true 130 | true 131 | WIN32;_CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 132 | true 133 | 134 | 135 | Console 136 | true 137 | true 138 | true 139 | $(ProjectDir)\..\..\$(TargetName)$(TargetExt) 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | -------------------------------------------------------------------------------- /nesasmsrc/vs/nesasm-vs.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | Source Files 38 | 39 | 40 | Source Files 41 | 42 | 43 | Source Files 44 | 45 | 46 | Source Files 47 | 48 | 49 | Source Files 50 | 51 | 52 | Source Files 53 | 54 | 55 | Source Files 56 | 57 | 58 | Source Files 59 | 60 | 61 | Source Files 62 | 63 | 64 | Source Files 65 | 66 | 67 | Source Files 68 | 69 | 70 | 71 | 72 | Header Files 73 | 74 | 75 | Header Files 76 | 77 | 78 | Header Files 79 | 80 | 81 | Header Files 82 | 83 | 84 | Header Files 85 | 86 | 87 | Header Files 88 | 89 | 90 | Header Files 91 | 92 | 93 | Header Files 94 | 95 | 96 | -------------------------------------------------------------------------------- /nss/intro-0.nam: -------------------------------------------------------------------------------- 1 |  2 |  !"#$% -------------------------------------------------------------------------------- /nss/intro-1.nam: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pellsson/aoc2021/e71a765ea4cd3293ac239f629dc87f45888fe470/nss/intro-1.nam -------------------------------------------------------------------------------- /nss/intro-2.nam: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pellsson/aoc2021/e71a765ea4cd3293ac239f629dc87f45888fe470/nss/intro-2.nam -------------------------------------------------------------------------------- /nss/intro-3.nam: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pellsson/aoc2021/e71a765ea4cd3293ac239f629dc87f45888fe470/nss/intro-3.nam -------------------------------------------------------------------------------- /nss/intro.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pellsson/aoc2021/e71a765ea4cd3293ac239f629dc87f45888fe470/nss/intro.chr -------------------------------------------------------------------------------- /nss/intro.nam: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pellsson/aoc2021/e71a765ea4cd3293ac239f629dc87f45888fe470/nss/intro.nam -------------------------------------------------------------------------------- /nss/intro.pal: -------------------------------------------------------------------------------- 1 | ')0!0!0!0 -------------------------------------------------------------------------------- /running.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pellsson/aoc2021/e71a765ea4cd3293ac239f629dc87f45888fe470/running.png -------------------------------------------------------------------------------- /scripts/intro-nt-fix.py: -------------------------------------------------------------------------------- 1 | x = open('nss/intro.nam', 'rb').read() 2 | x = list(x) 3 | for i in range(0x3C0+32+1, len(x)): 4 | x[i] = 0 5 | x = bytearray(x) 6 | open('nss/intro-0.nam', 'wb').write(x[0x000:0x100]) 7 | open('nss/intro-1.nam', 'wb').write(x[0x100:0x200]) 8 | open('nss/intro-2.nam', 'wb').write(x[0x200:0x300]) 9 | open('nss/intro-3.nam', 'wb').write(x[0x300:]) -------------------------------------------------------------------------------- /sym-fix.py: -------------------------------------------------------------------------------- 1 | import re 2 | import glob 3 | 4 | def expand_symbol(v, syms): 5 | if isinstance(v, int): 6 | return v 7 | v = v.replace('$', '0x') 8 | if v[0:2] == '0x': 9 | return int(v, 16) 10 | elif v[0] >= '0' and v[0] <= '9': 11 | return eval(v) 12 | tokens = v.split('+') 13 | if 1 == len(tokens): 14 | return expand_symbol(syms[tokens[0]], syms) 15 | return expand_symbol(tokens[0], syms) + expand_symbol(tokens[1], syms) 16 | 17 | def prg_syms(): 18 | for it in [ it.strip() for it in open('aoc.fns', 'r').readlines() ]: 19 | m = re.match(r'^([_a-zA-Z0-9]+)\s*= \$([a-fA-F0-9]+)$', it) 20 | if m is not None: 21 | print('PRG:%s:%s' % (m.group(1), m.group(2))) 22 | 23 | def write_syms(): 24 | syms = {} 25 | for it in ['aoc.asm', 'day14.asm']: # glob.glob('./*.asm'): 26 | m = re.findall(r'([_a-zA-Z0-9]+)\s*\.equ\s*([^;\n]+)', open(it, 'r').read()) 27 | if m is None: 28 | continue 29 | for x in m: 30 | syms[x[0].strip()] = x[1].strip() 31 | print('; ram') 32 | for k, v in syms.items(): 33 | syms[k] = expand_symbol(syms[k], syms) 34 | # print('WORK:%s:%04X' % (k, syms[k])) 35 | print('%s = $%04X' % (k, syms[k])) 36 | write_syms() 37 | 38 | ''' 39 | [('INPUT', 'WORK'), ('SAVED_SEQUENCE', 'WORK+$4')] 40 | [] 41 | [('INPUT', 'WORK'), ('SAVED_SEQUENCE', 'WORK+$4'), ('Pos', 'WORK+$8'), ('Depth', 'WORK+$C'), ('Aim', 'WORK+$10')] 42 | [] 43 | [('BANK_DAY1', '$0'), ('BANK_MUSIC', '$1'), ('CHR_AOC', '$0'), ('CHR_INTRO', '$2'), ('TMP', '$30'), ('ClobberWord0', '$32 ; and $3'), ('IntClobberWord0', '$34 ; and $5'), ('Param0', '$36'), ('Src', '$38'), ('SrcEnd', '$3A'), ('Dst', '$3C'), ('TaskResetStart', '$40'), ('MathLhs', '$40'), ('MathRhs', '$48'), ('MathOut', '$50'), ('Result', '$58 ; Hack.'), ('WORK', '$60'), ('TaskResetEnd', '$F0'), ('TaskIter', '$600'), ('TaskPtr', '$601'), ('TaskWait', '$604'), ('PrintPPU', '$680'), ('PrintQueue', '$682'), ('PrintData', '$683'), ('PrintColor', '$6F0'), ('PrintSaveX', '$6F1'), ('PrintSaveY', '$6F2'), ('PrintScrollDisabled', '$6F3'), ('PrintScrollTo', '$6F4'), ('PrintScrollAt', '$6F5'), ('Mirror2000', '$6F6'), ('IntrX', '$6F7'), ('IntrY', '$6F8'), ('FrameStartLo', '$6F9'), ('FrameStartHi', '$6FA'), ('FrameEndLo', '$6FB'), ('FrameEndHi', '$6FC'), ('FrameCounterLo', '$6FD'), ('FrameCounterHi', '$6FE'), ('CurrentBank', '$6FF'), ('SCROLL_SPEED', '2'), ('NUM_X_TILES', '32'), ('FONT_MAP_SIZE', '77'), ('FONT_MAP_START', '21'), ('MAX_MESSAGE_LEN', '32')] 44 | [('INPUT', 'WORK'), ('HighMask', 'WORK+$4'), ('Diff', 'WORK+$6 ; and 7'), ('V', 'WORK+$8'), ('CountMask', 'WORK+$9'), ('IsHigh', 'WORK+$a'), ('Mask', 'WORK+$10 ; and 11'), ('G', 'WORK+$12'), ('Remaining', 'WORK+$14 ; and 15'), ('KeepValue', 'WORK+$16'), ('PtrHighByte', 'WORK+$18'), ('WantMany', 'WORK+$19')] 45 | ''' -------------------------------------------------------------------------------- /title.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pellsson/aoc2021/e71a765ea4cd3293ac239f629dc87f45888fe470/title.bmp -------------------------------------------------------------------------------- /title.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pellsson/aoc2021/e71a765ea4cd3293ac239f629dc87f45888fe470/title.xcf --------------------------------------------------------------------------------