beebasm
changeset 34:5aca9d5e4d02
Beginning of macro implementation
Some small bugfixes and improvements to line parser
Added some more error messages
Renamed the demo source file extensions from .asm (too generic) to .6502 (better)
| author | RichTW <richtw1@gmail.com> |
|---|---|
| date | Sun Mar 06 18:19:27 2011 +0100 |
| parents | 58954bd1a2d9 |
| children | 5fedd5b15bd7 |
| files | demo.6502 demo.asm relocdemo.6502 relocdemo.asm src/Makefile src/Makefile.inc src/VS2010/BeebAsm.vcxproj src/VS2010/BeebAsm.vcxproj.filters src/asmexception.h src/commands.cpp src/lineparser.cpp src/lineparser.h src/macro.cpp src/macro.h src/main.cpp src/sourcefile.cpp src/sourcefile.h src/tokens.h |
| diffstat | 18 files changed, 1480 insertions(+), 1093 deletions(-) [+] |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/demo.6502 Sun Mar 06 18:19:27 2011 +0100 1.3 @@ -0,0 +1,477 @@ 1.4 +\ ****************************************************************** 1.5 +\ * 1.6 +\ * BeebAsm demo 1.7 +\ * 1.8 +\ * Spinning star globe 1.9 +\ * 1.10 +\ * Change the speed of rotation with Z and X keys 1.11 +\ * Press Esc to quit 1.12 +\ * 1.13 +\ * Try assembling the code with debugrasters = TRUE (line 20) 1.14 +\ * It shows how the frame is split up into various stages of 1.15 +\ * processing. 1.16 +\ * 1.17 +\ * The red part is where we start to plot the dots - starting as 1.18 +\ * soon before the first screenline of the next frame is rastered 1.19 +\ * as possible. 1.20 +\ * 1.21 +\ * The magenta part is a small loop where we wait for 'vsync'. 1.22 +\ * It's not actually vsync, but in fact a fixed time from actual 1.23 +\ * vsync (timed by timer 1) from which point we can start to erase 1.24 +\ * points from the top of the screen down. 1.25 +\ * 1.26 +\ * The blue part is the time when we are erasing dots. Because 1.27 +\ * the dots are sorted from top to bottom of screen, we can 1.28 +\ * overlap these updates with the actual screen rasterisation. 1.29 +\ * 1.30 +\ ****************************************************************** 1.31 + 1.32 +\\ Define globals 1.33 + 1.34 +numdots = 160 1.35 +radius = 100 1.36 +timerlength = 64*8*26 1.37 +debugrasters = FALSE 1.38 + 1.39 + 1.40 +\\ Define some zp locations 1.41 + 1.42 +ORG 0 1.43 + 1.44 +.xpos SKIP 1 1.45 +.ypos SKIP 1 1.46 +.colour SKIP 1 1.47 +.write SKIP 2 1.48 +.vsync SKIP 1 1.49 +.angle SKIP 2 1.50 +.speed SKIP 2 1.51 +.counter SKIP 1 1.52 +.temp SKIP 1 1.53 +.behindflag SKIP 1 1.54 + 1.55 + 1.56 +\\ Set start address 1.57 + 1.58 +ORG &1100 1.59 + 1.60 +\ ****************************************************************** 1.61 +\ * The entry point of the demo 1.62 +\ ****************************************************************** 1.63 + 1.64 +.start 1.65 + 1.66 + \\ Set up hardware state and interrupts 1.67 + 1.68 + SEI 1.69 + LDX #&FF:TXS ; reset stack 1.70 + STX &FE44:STX &FE45 1.71 + LDA #&7F:STA &FE4E ; disable all interrupts 1.72 + STA &FE43 ; set keyboard data direction 1.73 + LDA #&C2:STA &FE4E ; enable VSync and timer interrupt 1.74 + LDA #&0F:STA &FE42 ; set addressable latch for writing 1.75 + LDA #3:STA &FE40 ; keyboard write enable 1.76 + LDA #0:STA &FE4B ; timer 1 one shot mode 1.77 + LDA #LO(irq):STA &204 1.78 + LDA #HI(irq):STA &205 ; set interrupt handler 1.79 + 1.80 + \\ Clear the screen 1.81 + 1.82 + LDX #&40 1.83 + LDA #0 1.84 + TAY 1.85 +.clearloop 1.86 + STA &4000,Y 1.87 + INY 1.88 + BNE clearloop 1.89 + INC clearloop+2 1.90 + DEX 1.91 + BNE clearloop 1.92 + 1.93 + \\ Set up CRTC for MODE 2 1.94 + 1.95 + LDX #13 1.96 +.crtcloop 1.97 + STX &FE00 1.98 + LDA crtcregs,X 1.99 + STA &FE01 1.100 + DEX 1.101 + BPL crtcloop 1.102 + 1.103 + \\ Set up video ULA for MODE 2 1.104 + 1.105 + LDA #&F4 1.106 + STA &FE20 1.107 + 1.108 + \\ Set up palette for MODE 2 1.109 + 1.110 + LDX #15 1.111 +.palloop 1.112 + LDA paldata,X 1.113 + STA &FE21 1.114 + ORA #&80 1.115 + STA &FE21 1.116 + DEX 1.117 + BPL palloop 1.118 + 1.119 + \\ Initialise vars 1.120 + 1.121 + LDA #0:STA angle:STA angle+1 1.122 + STA vsync 1.123 + STA speed 1.124 + LDA #1:STA speed+1 1.125 + 1.126 + \\ Enable interrupts, ready to start the main loop 1.127 + 1.128 + CLI 1.129 + 1.130 + \\ First we wait for 'vsync' so we are synchronised 1.131 + 1.132 +.initialwait 1.133 + LDA vsync:BEQ initialwait:LDA #0:STA vsync 1.134 + 1.135 + \\ This is the main loop! 1.136 + 1.137 +.mainloop 1.138 + 1.139 + \\ Plot every dot on the screen 1.140 + 1.141 + LDX #0 1.142 +.plotdotloop 1.143 + STX counter 1.144 + 1.145 + ; setup y pos ready for plot routine 1.146 + 1.147 + LDA doty,X:STA ypos 1.148 + 1.149 + ; get sin index 1.150 + 1.151 + CLC:LDA dotx,X:ADC angle+1:TAY 1.152 + CLC:ADC #64:STA behindflag 1.153 + 1.154 + ; get colour from sin index 1.155 + 1.156 + LDA coltable,Y:STA colour 1.157 + 1.158 + ; perform sin(x) * radius 1.159 + ; discussion of the multiplication method below in the table setup 1.160 + 1.161 + SEC:LDA sintable,Y:STA temp:SBC dotr,X 1.162 + BCS noneg:EOR #&FF:ADC #1:.noneg 1.163 + CPY #128:TAY:BCS negativesine 1.164 + 1.165 + CLC:LDA dotr,X:ADC temp:TAX 1.166 + BCS morethan256:SEC 1.167 + LDA multtab1,X:SBC multtab1,Y:JMP donemult 1.168 + .morethan256 1.169 + LDA multtab2,X:SBC multtab1,Y:JMP donemult 1.170 + 1.171 + .negativesine 1.172 + CLC:LDA dotr,X:ADC temp:TAX 1.173 + BCS morethan256b:SEC 1.174 + LDA multtab1,Y:SBC multtab1,X:JMP donemult 1.175 + .morethan256b 1.176 + LDA multtab1,Y:SBC multtab2,X 1.177 + .donemult 1.178 + 1.179 + CLC:ADC #64:STA xpos 1.180 + 1.181 + ; routine to plot a dot 1.182 + ; also we remember the calculated screen address in the dot tables 1.183 + 1.184 + LDA ypos:LSR A:LSR A:AND #&FE 1.185 + TAX 1.186 + LDA xpos:AND #&FE:ASL A:ASL A 1.187 + STA write 1.188 + LDY counter:STA olddotaddrlo,Y 1.189 + TXA:ADC #&40:STA write+1:STA olddotaddrhi,Y 1.190 + LDA ypos:AND #7:STA olddotaddry,Y:TAY 1.191 + LDA xpos:LSR A:LDA colour:ROL A:TAX 1.192 + LDA colours,X 1.193 + ORA (write),Y 1.194 + STA (write),Y 1.195 + BIT behindflag:BMI behind 1.196 + 1.197 + ; if the dot is in front, we double its size 1.198 + 1.199 + DEY:BPL samescreenrow 1.200 + DEC write+1:DEC write+1:LDY #7:.samescreenrow 1.201 + LDA colours,X 1.202 + ORA (write),Y 1.203 + STA (write),Y 1.204 + .behind 1.205 + 1.206 + ; loop to the next dot 1.207 + 1.208 + LDX counter 1.209 + INX:CPX #numdots 1.210 + BEQ waitforvsync 1.211 + JMP plotdotloop 1.212 + 1.213 + \\ Wait for VSync here 1.214 + 1.215 +.waitforvsync 1.216 + IF debugrasters 1.217 + LDA #&00 + PAL_magenta:STA &FE21 1.218 + ENDIF 1.219 +.waitingforvsync 1.220 + LDA vsync:BEQ waitingforvsync 1.221 + CMP #2:BCS exit ; insist that it runs in a frame! 1.222 + LDA #0:STA vsync 1.223 + 1.224 + \\ Now delete all the old dots. 1.225 + \\ We actually do this when the screen is still rasterising down..! 1.226 + 1.227 + TAX 1.228 +.eraseloop 1.229 + LDY olddotaddrlo,X:STY write 1.230 + LDY olddotaddrhi,X:STY write+1 1.231 + LDY olddotaddry,X 1.232 + STA (write),Y 1.233 + DEY:BPL erasesamerow 1.234 + DEC write+1:DEC write+1:LDY #7:.erasesamerow 1.235 + STA (write),Y 1.236 + INX:CPX #numdots 1.237 + BNE eraseloop 1.238 + 1.239 + IF debugrasters 1.240 + LDA #&00 + PAL_red:STA &FE21 1.241 + ENDIF 1.242 + 1.243 + \\ Add to rotation 1.244 + 1.245 + CLC:LDA angle:ADC speed:STA angle 1.246 + LDA angle+1:ADC speed+1:STA angle+1 1.247 + 1.248 + \\ Check keypresses 1.249 + 1.250 + LDA #66:STA &FE4F:LDA &FE4F:BPL notx 1.251 + CLC:LDA speed:ADC #16:STA speed:BCC notx:INC speed+1:.notx 1.252 + LDA #97:STA &FE4F:LDA &FE4F:BPL notz 1.253 + SEC:LDA speed:SBC #16:STA speed:BCS notz:DEC speed+1:.notz 1.254 + LDA #112:STA &FE4F:LDA &FE4F:BMI exit 1.255 + 1.256 + JMP mainloop 1.257 + 1.258 + \\ Exit - in the least graceful way possible :) 1.259 + 1.260 +.exit 1.261 + JMP (&FFFC) 1.262 + 1.263 + 1.264 + 1.265 +\ ****************************************************************** 1.266 +\ * IRQ handler 1.267 +\ ****************************************************************** 1.268 + 1.269 +.irq 1.270 + LDA &FE4D:AND #2:BNE irqvsync 1.271 +.irqtimer 1.272 + LDA #&40:STA &FE4D:INC vsync 1.273 + IF debugrasters 1.274 + LDA #&00 + PAL_blue:STA &FE21 1.275 + ENDIF 1.276 + LDA &FC 1.277 + RTI 1.278 +.irqvsync 1.279 + STA &FE4D 1.280 + LDA #LO(timerlength):STA &FE44 1.281 + LDA #HI(timerlength):STA &FE45 1.282 + IF debugrasters 1.283 + LDA #&00 + PAL_black:STA &FE21 1.284 + ENDIF 1.285 + LDA &FC 1.286 + RTI 1.287 + 1.288 + 1.289 + 1.290 +\ ****************************************************************** 1.291 +\ * Colour table used by the plot code 1.292 +\ ****************************************************************** 1.293 + 1.294 +.colours 1.295 + EQUB &00, &00 ; black pixels 1.296 + EQUB &02, &01 ; blue pixels 1.297 + EQUB &08, &04 ; red pixels 1.298 + EQUB &0A, &05 ; magenta pixels 1.299 + EQUB &20, &10 ; green pixels 1.300 + EQUB &22, &11 ; cyan pixels 1.301 + EQUB &28, &14 ; yellow pixels 1.302 + EQUB &2A, &15 ; white pixels 1.303 + 1.304 + 1.305 + 1.306 +\ ****************************************************************** 1.307 +\ * Values of CRTC regs for MODE 2 1.308 +\ ****************************************************************** 1.309 + 1.310 +.crtcregs 1.311 + EQUB 127 ; R0 horizontal total 1.312 + EQUB 64 ; R1 horizontal displayed - shrunk a little 1.313 + EQUB 91 ; R2 horizontal position 1.314 + EQUB 40 ; R3 sync width 1.315 + EQUB 38 ; R4 vertical total 1.316 + EQUB 0 ; R5 vertical total adjust 1.317 + EQUB 32 ; R6 vertical displayed 1.318 + EQUB 34 ; R7 vertical position 1.319 + EQUB 0 ; R8 interlace 1.320 + EQUB 7 ; R9 scanlines per row 1.321 + EQUB 32 ; R10 cursor start 1.322 + EQUB 8 ; R11 cursor end 1.323 + EQUB HI(&4000/8) ; R12 screen start address, high 1.324 + EQUB LO(&4000/8) ; R13 screen start address, low 1.325 + 1.326 + 1.327 +\ ****************************************************************** 1.328 +\ * Values of palette regs for MODE 2 1.329 +\ ****************************************************************** 1.330 + 1.331 +PAL_black = (0 EOR 7) 1.332 +PAL_blue = (4 EOR 7) 1.333 +PAL_red = (1 EOR 7) 1.334 +PAL_magenta = (5 EOR 7) 1.335 +PAL_green = (2 EOR 7) 1.336 +PAL_cyan = (6 EOR 7) 1.337 +PAL_yellow = (3 EOR 7) 1.338 +PAL_white = (7 EOR 7) 1.339 + 1.340 +.paldata 1.341 + EQUB &00 + PAL_black 1.342 + EQUB &10 + PAL_blue 1.343 + EQUB &20 + PAL_red 1.344 + EQUB &30 + PAL_magenta 1.345 + EQUB &40 + PAL_green 1.346 + EQUB &50 + PAL_cyan 1.347 + EQUB &60 + PAL_yellow 1.348 + EQUB &70 + PAL_white 1.349 + 1.350 + 1.351 + 1.352 +\ ****************************************************************** 1.353 +\ * sin table 1.354 +\ ****************************************************************** 1.355 + 1.356 +; contains ABS sine values 1.357 +; we don't store the sign as it confuses the multiplication. 1.358 +; we can tell the sign very easily from whether the index is >128 1.359 + 1.360 +ALIGN &100 ; so we don't incur page-crossed penalties 1.361 +.sintable 1.362 +FOR n, 0, 255 1.363 + EQUB ABS(SIN(n/128*PI)) * 255 1.364 +NEXT 1.365 + 1.366 + 1.367 +\ ****************************************************************** 1.368 +\ * colour table 1.369 +\ ****************************************************************** 1.370 + 1.371 +ALIGN &100 1.372 +.coltable 1.373 +FOR n, 0, 255 1.374 + EQUB (SIN(n/128*PI) + 1) / 2.0001 * 7 + 1 1.375 +NEXT 1.376 + 1.377 + 1.378 +\ ****************************************************************** 1.379 +\ * multiplication tables 1.380 +\ ****************************************************************** 1.381 + 1.382 +; This is a very quick way to do multiplies, based on the fact that: 1.383 +; 1.384 +; (a+b)^2 = a^2 + b^2 + 2ab (I) 1.385 +; (a-b)^2 = a^2 + b^2 - 2ab (II) 1.386 +; 1.387 +; (I) minus (II) yields: (a+b)^2 - (a-b)^2 = 4ab 1.388 +; 1.389 +; or, rewritten: ab = f(a+b) - f(a-b), 1.390 +; where f(x) = x^2 / 4 1.391 +; 1.392 +; We build a table of f(x) here with x=0..511, and then can perform 1.393 +; 8-bit * 8-bit by 4 table lookups and a 16-bit subtract. 1.394 +; 1.395 +; In this case, we will discard the low byte of the result, so we 1.396 +; only need the high bytes, and can do just 2 table lookups and a 1.397 +; simple 8-bit subtract. 1.398 + 1.399 +ALIGN &100 1.400 +.multtab1 1.401 +FOR n, 0, 255 1.402 + EQUB HI(n*n DIV 4) 1.403 +NEXT 1.404 +.multtab2 1.405 +FOR n, 256, 511 1.406 + EQUB HI(n*n DIV 4) 1.407 +NEXT 1.408 + 1.409 + 1.410 +\ ****************************************************************** 1.411 +\ * dot tables 1.412 +\ ****************************************************************** 1.413 + 1.414 +; contains the phase of this dot 1.415 + 1.416 +ALIGN &100 1.417 +.dotx 1.418 +FOR n, 0, numdots-1 1.419 + EQUB RND(256) 1.420 +NEXT 1.421 + 1.422 + 1.423 +; contains the y position of the dot 1.424 +; the dots are sorted by y positions, highest on screen first - this means we can do 1.425 +; 'raster chasing'! 1.426 +; the y positions are also biased so there are fewer at the poles, and more at the equator! 1.427 + 1.428 +ALIGN &100 1.429 +.doty 1.430 +FOR n, 0, numdots-1 1.431 + x = (n - numdots/2 + 0.5) / (numdots/2) 1.432 + y = (x - SIN(x*PI) * 0.1) * radius 1.433 + EQUB 128 + y 1.434 +NEXT 1.435 + 1.436 + 1.437 +; contains the radius of the ball at this y position 1.438 + 1.439 +ALIGN &100 1.440 +.dotr 1.441 +FOR n, 0, numdots-1 1.442 + x = (n - numdots/2 + 0.5) / (numdots/2) 1.443 + y = (x - SIN(x*PI) * 0.1) * radius 1.444 + r = SQR(radius*radius - y*y) / 2 1.445 + EQUB r 1.446 +NEXT 1.447 + 1.448 + 1.449 +\ ****************************************************************** 1.450 +\ * End address to be saved 1.451 +\ ****************************************************************** 1.452 +.end 1.453 + 1.454 + 1.455 + 1.456 +\ ****************************************************************** 1.457 +\ * Space reserved for tables but not initialised with anything 1.458 +\ * Therefore these are not saved in the executable 1.459 +\ ****************************************************************** 1.460 + 1.461 +; these store the screen address of the last dot 1.462 +; at the end of the frame, we go through these tables, storing zeroes to 1.463 +; all these addresses in order to delete the last frame 1.464 + 1.465 +ALIGN &100 1.466 +.olddotaddrlo SKIP numdots 1.467 + 1.468 +ALIGN &100 1.469 +.olddotaddrhi SKIP numdots 1.470 + 1.471 +ALIGN &100 1.472 +.olddotaddry SKIP numdots 1.473 + 1.474 + 1.475 + 1.476 +\ ****************************************************************** 1.477 +\ * Save the code 1.478 +\ ****************************************************************** 1.479 + 1.480 +SAVE "Code", start, end
2.1 --- a/demo.asm Fri Mar 04 02:01:51 2011 +0000 2.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 2.3 @@ -1,477 +0,0 @@ 2.4 -\ ****************************************************************** 2.5 -\ * 2.6 -\ * BeebAsm demo 2.7 -\ * 2.8 -\ * Spinning star globe 2.9 -\ * 2.10 -\ * Change the speed of rotation with Z and X keys 2.11 -\ * Press Esc to quit 2.12 -\ * 2.13 -\ * Try assembling the code with debugrasters = TRUE (line 20) 2.14 -\ * It shows how the frame is split up into various stages of 2.15 -\ * processing. 2.16 -\ * 2.17 -\ * The red part is where we start to plot the dots - starting as 2.18 -\ * soon before the first screenline of the next frame is rastered 2.19 -\ * as possible. 2.20 -\ * 2.21 -\ * The magenta part is a small loop where we wait for 'vsync'. 2.22 -\ * It's not actually vsync, but in fact a fixed time from actual 2.23 -\ * vsync (timed by timer 1) from which point we can start to erase 2.24 -\ * points from the top of the screen down. 2.25 -\ * 2.26 -\ * The blue part is the time when we are erasing dots. Because 2.27 -\ * the dots are sorted from top to bottom of screen, we can 2.28 -\ * overlap these updates with the actual screen rasterisation. 2.29 -\ * 2.30 -\ ****************************************************************** 2.31 - 2.32 -\\ Define globals 2.33 - 2.34 -numdots = 160 2.35 -radius = 100 2.36 -timerlength = 64*8*26 2.37 -debugrasters = FALSE 2.38 - 2.39 - 2.40 -\\ Define some zp locations 2.41 - 2.42 -ORG 0 2.43 - 2.44 -.xpos SKIP 1 2.45 -.ypos SKIP 1 2.46 -.colour SKIP 1 2.47 -.write SKIP 2 2.48 -.vsync SKIP 1 2.49 -.angle SKIP 2 2.50 -.speed SKIP 2 2.51 -.counter SKIP 1 2.52 -.temp SKIP 1 2.53 -.behindflag SKIP 1 2.54 - 2.55 - 2.56 -\\ Set start address 2.57 - 2.58 -ORG &1100 2.59 - 2.60 -\ ****************************************************************** 2.61 -\ * The entry point of the demo 2.62 -\ ****************************************************************** 2.63 - 2.64 -.start 2.65 - 2.66 - \\ Set up hardware state and interrupts 2.67 - 2.68 - SEI 2.69 - LDX #&FF:TXS ; reset stack 2.70 - STX &FE44:STX &FE45 2.71 - LDA #&7F:STA &FE4E ; disable all interrupts 2.72 - STA &FE43 ; set keyboard data direction 2.73 - LDA #&C2:STA &FE4E ; enable VSync and timer interrupt 2.74 - LDA #&0F:STA &FE42 ; set addressable latch for writing 2.75 - LDA #3:STA &FE40 ; keyboard write enable 2.76 - LDA #0:STA &FE4B ; timer 1 one shot mode 2.77 - LDA #LO(irq):STA &204 2.78 - LDA #HI(irq):STA &205 ; set interrupt handler 2.79 - 2.80 - \\ Clear the screen 2.81 - 2.82 - LDX #&40 2.83 - LDA #0 2.84 - TAY 2.85 -.clearloop 2.86 - STA &4000,Y 2.87 - INY 2.88 - BNE clearloop 2.89 - INC clearloop+2 2.90 - DEX 2.91 - BNE clearloop 2.92 - 2.93 - \\ Set up CRTC for MODE 2 2.94 - 2.95 - LDX #13 2.96 -.crtcloop 2.97 - STX &FE00 2.98 - LDA crtcregs,X 2.99 - STA &FE01 2.100 - DEX 2.101 - BPL crtcloop 2.102 - 2.103 - \\ Set up video ULA for MODE 2 2.104 - 2.105 - LDA #&F4 2.106 - STA &FE20 2.107 - 2.108 - \\ Set up palette for MODE 2 2.109 - 2.110 - LDX #15 2.111 -.palloop 2.112 - LDA paldata,X 2.113 - STA &FE21 2.114 - ORA #&80 2.115 - STA &FE21 2.116 - DEX 2.117 - BPL palloop 2.118 - 2.119 - \\ Initialise vars 2.120 - 2.121 - LDA #0:STA angle:STA angle+1 2.122 - STA vsync 2.123 - STA speed 2.124 - LDA #1:STA speed+1 2.125 - 2.126 - \\ Enable interrupts, ready to start the main loop 2.127 - 2.128 - CLI 2.129 - 2.130 - \\ First we wait for 'vsync' so we are synchronised 2.131 - 2.132 -.initialwait 2.133 - LDA vsync:BEQ initialwait:LDA #0:STA vsync 2.134 - 2.135 - \\ This is the main loop! 2.136 - 2.137 -.mainloop 2.138 - 2.139 - \\ Plot every dot on the screen 2.140 - 2.141 - LDX #0 2.142 -.plotdotloop 2.143 - STX counter 2.144 - 2.145 - ; setup y pos ready for plot routine 2.146 - 2.147 - LDA doty,X:STA ypos 2.148 - 2.149 - ; get sin index 2.150 - 2.151 - CLC:LDA dotx,X:ADC angle+1:TAY 2.152 - CLC:ADC #64:STA behindflag 2.153 - 2.154 - ; get colour from sin index 2.155 - 2.156 - LDA coltable,Y:STA colour 2.157 - 2.158 - ; perform sin(x) * radius 2.159 - ; discussion of the multiplication method below in the table setup 2.160 - 2.161 - SEC:LDA sintable,Y:STA temp:SBC dotr,X 2.162 - BCS noneg:EOR #&FF:ADC #1:.noneg 2.163 - CPY #128:TAY:BCS negativesine 2.164 - 2.165 - CLC:LDA dotr,X:ADC temp:TAX 2.166 - BCS morethan256:SEC 2.167 - LDA multtab1,X:SBC multtab1,Y:JMP donemult 2.168 - .morethan256 2.169 - LDA multtab2,X:SBC multtab1,Y:JMP donemult 2.170 - 2.171 - .negativesine 2.172 - CLC:LDA dotr,X:ADC temp:TAX 2.173 - BCS morethan256b:SEC 2.174 - LDA multtab1,Y:SBC multtab1,X:JMP donemult 2.175 - .morethan256b 2.176 - LDA multtab1,Y:SBC multtab2,X 2.177 - .donemult 2.178 - 2.179 - CLC:ADC #64:STA xpos 2.180 - 2.181 - ; routine to plot a dot 2.182 - ; also we remember the calculated screen address in the dot tables 2.183 - 2.184 - LDA ypos:LSR A:LSR A:AND #&FE 2.185 - TAX 2.186 - LDA xpos:AND #&FE:ASL A:ASL A 2.187 - STA write 2.188 - LDY counter:STA olddotaddrlo,Y 2.189 - TXA:ADC #&40:STA write+1:STA olddotaddrhi,Y 2.190 - LDA ypos:AND #7:STA olddotaddry,Y:TAY 2.191 - LDA xpos:LSR A:LDA colour:ROL A:TAX 2.192 - LDA colours,X 2.193 - ORA (write),Y 2.194 - STA (write),Y 2.195 - BIT behindflag:BMI behind 2.196 - 2.197 - ; if the dot is in front, we double its size 2.198 - 2.199 - DEY:BPL samescreenrow 2.200 - DEC write+1:DEC write+1:LDY #7:.samescreenrow 2.201 - LDA colours,X 2.202 - ORA (write),Y 2.203 - STA (write),Y 2.204 - .behind 2.205 - 2.206 - ; loop to the next dot 2.207 - 2.208 - LDX counter 2.209 - INX:CPX #numdots 2.210 - BEQ waitforvsync 2.211 - JMP plotdotloop 2.212 - 2.213 - \\ Wait for VSync here 2.214 - 2.215 -.waitforvsync 2.216 - IF debugrasters 2.217 - LDA #&00 + PAL_magenta:STA &FE21 2.218 - ENDIF 2.219 -.waitingforvsync 2.220 - LDA vsync:BEQ waitingforvsync 2.221 - CMP #2:BCS exit ; insist that it runs in a frame! 2.222 - LDA #0:STA vsync 2.223 - 2.224 - \\ Now delete all the old dots. 2.225 - \\ We actually do this when the screen is still rasterising down..! 2.226 - 2.227 - TAX 2.228 -.eraseloop 2.229 - LDY olddotaddrlo,X:STY write 2.230 - LDY olddotaddrhi,X:STY write+1 2.231 - LDY olddotaddry,X 2.232 - STA (write),Y 2.233 - DEY:BPL erasesamerow 2.234 - DEC write+1:DEC write+1:LDY #7:.erasesamerow 2.235 - STA (write),Y 2.236 - INX:CPX #numdots 2.237 - BNE eraseloop 2.238 - 2.239 - IF debugrasters 2.240 - LDA #&00 + PAL_red:STA &FE21 2.241 - ENDIF 2.242 - 2.243 - \\ Add to rotation 2.244 - 2.245 - CLC:LDA angle:ADC speed:STA angle 2.246 - LDA angle+1:ADC speed+1:STA angle+1 2.247 - 2.248 - \\ Check keypresses 2.249 - 2.250 - LDA #66:STA &FE4F:LDA &FE4F:BPL notx 2.251 - CLC:LDA speed:ADC #16:STA speed:BCC notx:INC speed+1:.notx 2.252 - LDA #97:STA &FE4F:LDA &FE4F:BPL notz 2.253 - SEC:LDA speed:SBC #16:STA speed:BCS notz:DEC speed+1:.notz 2.254 - LDA #112:STA &FE4F:LDA &FE4F:BMI exit 2.255 - 2.256 - JMP mainloop 2.257 - 2.258 - \\ Exit - in the least graceful way possible :) 2.259 - 2.260 -.exit 2.261 - JMP (&FFFC) 2.262 - 2.263 - 2.264 - 2.265 -\ ****************************************************************** 2.266 -\ * IRQ handler 2.267 -\ ****************************************************************** 2.268 - 2.269 -.irq 2.270 - LDA &FE4D:AND #2:BNE irqvsync 2.271 -.irqtimer 2.272 - LDA #&40:STA &FE4D:INC vsync 2.273 - IF debugrasters 2.274 - LDA #&00 + PAL_blue:STA &FE21 2.275 - ENDIF 2.276 - LDA &FC 2.277 - RTI 2.278 -.irqvsync 2.279 - STA &FE4D 2.280 - LDA #LO(timerlength):STA &FE44 2.281 - LDA #HI(timerlength):STA &FE45 2.282 - IF debugrasters 2.283 - LDA #&00 + PAL_black:STA &FE21 2.284 - ENDIF 2.285 - LDA &FC 2.286 - RTI 2.287 - 2.288 - 2.289 - 2.290 -\ ****************************************************************** 2.291 -\ * Colour table used by the plot code 2.292 -\ ****************************************************************** 2.293 - 2.294 -.colours 2.295 - EQUB &00, &00 ; black pixels 2.296 - EQUB &02, &01 ; blue pixels 2.297 - EQUB &08, &04 ; red pixels 2.298 - EQUB &0A, &05 ; magenta pixels 2.299 - EQUB &20, &10 ; green pixels 2.300 - EQUB &22, &11 ; cyan pixels 2.301 - EQUB &28, &14 ; yellow pixels 2.302 - EQUB &2A, &15 ; white pixels 2.303 - 2.304 - 2.305 - 2.306 -\ ****************************************************************** 2.307 -\ * Values of CRTC regs for MODE 2 2.308 -\ ****************************************************************** 2.309 - 2.310 -.crtcregs 2.311 - EQUB 127 ; R0 horizontal total 2.312 - EQUB 64 ; R1 horizontal displayed - shrunk a little 2.313 - EQUB 91 ; R2 horizontal position 2.314 - EQUB 40 ; R3 sync width 2.315 - EQUB 38 ; R4 vertical total 2.316 - EQUB 0 ; R5 vertical total adjust 2.317 - EQUB 32 ; R6 vertical displayed 2.318 - EQUB 34 ; R7 vertical position 2.319 - EQUB 0 ; R8 interlace 2.320 - EQUB 7 ; R9 scanlines per row 2.321 - EQUB 32 ; R10 cursor start 2.322 - EQUB 8 ; R11 cursor end 2.323 - EQUB HI(&4000/8) ; R12 screen start address, high 2.324 - EQUB LO(&4000/8) ; R13 screen start address, low 2.325 - 2.326 - 2.327 -\ ****************************************************************** 2.328 -\ * Values of palette regs for MODE 2 2.329 -\ ****************************************************************** 2.330 - 2.331 -PAL_black = (0 EOR 7) 2.332 -PAL_blue = (4 EOR 7) 2.333 -PAL_red = (1 EOR 7) 2.334 -PAL_magenta = (5 EOR 7) 2.335 -PAL_green = (2 EOR 7) 2.336 -PAL_cyan = (6 EOR 7) 2.337 -PAL_yellow = (3 EOR 7) 2.338 -PAL_white = (7 EOR 7) 2.339 - 2.340 -.paldata 2.341 - EQUB &00 + PAL_black 2.342 - EQUB &10 + PAL_blue 2.343 - EQUB &20 + PAL_red 2.344 - EQUB &30 + PAL_magenta 2.345 - EQUB &40 + PAL_green 2.346 - EQUB &50 + PAL_cyan 2.347 - EQUB &60 + PAL_yellow 2.348 - EQUB &70 + PAL_white 2.349 - 2.350 - 2.351 - 2.352 -\ ****************************************************************** 2.353 -\ * sin table 2.354 -\ ****************************************************************** 2.355 - 2.356 -; contains ABS sine values 2.357 -; we don't store the sign as it confuses the multiplication. 2.358 -; we can tell the sign very easily from whether the index is >128 2.359 - 2.360 -ALIGN &100 ; so we don't incur page-crossed penalties 2.361 -.sintable 2.362 -FOR n, 0, 255 2.363 - EQUB ABS(SIN(n/128*PI)) * 255 2.364 -NEXT 2.365 - 2.366 - 2.367 -\ ****************************************************************** 2.368 -\ * colour table 2.369 -\ ****************************************************************** 2.370 - 2.371 -ALIGN &100 2.372 -.coltable 2.373 -FOR n, 0, 255 2.374 - EQUB (SIN(n/128*PI) + 1) / 2.0001 * 7 + 1 2.375 -NEXT 2.376 - 2.377 - 2.378 -\ ****************************************************************** 2.379 -\ * multiplication tables 2.380 -\ ****************************************************************** 2.381 - 2.382 -; This is a very quick way to do multiplies, based on the fact that: 2.383 -; 2.384 -; (a+b)^2 = a^2 + b^2 + 2ab (I) 2.385 -; (a-b)^2 = a^2 + b^2 - 2ab (II) 2.386 -; 2.387 -; (I) minus (II) yields: (a+b)^2 - (a-b)^2 = 4ab 2.388 -; 2.389 -; or, rewritten: ab = f(a+b) - f(a-b), 2.390 -; where f(x) = x^2 / 4 2.391 -; 2.392 -; We build a table of f(x) here with x=0..511, and then can perform 2.393 -; 8-bit * 8-bit by 4 table lookups and a 16-bit subtract. 2.394 -; 2.395 -; In this case, we will discard the low byte of the result, so we 2.396 -; only need the high bytes, and can do just 2 table lookups and a 2.397 -; simple 8-bit subtract. 2.398 - 2.399 -ALIGN &100 2.400 -.multtab1 2.401 -FOR n, 0, 255 2.402 - EQUB HI(n*n DIV 4) 2.403 -NEXT 2.404 -.multtab2 2.405 -FOR n, 256, 511 2.406 - EQUB HI(n*n DIV 4) 2.407 -NEXT 2.408 - 2.409 - 2.410 -\ ****************************************************************** 2.411 -\ * dot tables 2.412 -\ ****************************************************************** 2.413 - 2.414 -; contains the phase of this dot 2.415 - 2.416 -ALIGN &100 2.417 -.dotx 2.418 -FOR n, 0, numdots-1 2.419 - EQUB RND(256) 2.420 -NEXT 2.421 - 2.422 - 2.423 -; contains the y position of the dot 2.424 -; the dots are sorted by y positions, highest on screen first - this means we can do 2.425 -; 'raster chasing'! 2.426 -; the y positions are also biased so there are fewer at the poles, and more at the equator! 2.427 - 2.428 -ALIGN &100 2.429 -.doty 2.430 -FOR n, 0, numdots-1 2.431 - x = (n - numdots/2 + 0.5) / (numdots/2) 2.432 - y = (x - SIN(x*PI) * 0.1) * radius 2.433 - EQUB 128 + y 2.434 -NEXT 2.435 - 2.436 - 2.437 -; contains the radius of the ball at this y position 2.438 - 2.439 -ALIGN &100 2.440 -.dotr 2.441 -FOR n, 0, numdots-1 2.442 - x = (n - numdots/2 + 0.5) / (numdots/2) 2.443 - y = (x - SIN(x*PI) * 0.1) * radius 2.444 - r = SQR(radius*radius - y*y) / 2 2.445 - EQUB r 2.446 -NEXT 2.447 - 2.448 - 2.449 -\ ****************************************************************** 2.450 -\ * End address to be saved 2.451 -\ ****************************************************************** 2.452 -.end 2.453 - 2.454 - 2.455 - 2.456 -\ ****************************************************************** 2.457 -\ * Space reserved for tables but not initialised with anything 2.458 -\ * Therefore these are not saved in the executable 2.459 -\ ****************************************************************** 2.460 - 2.461 -; these store the screen address of the last dot 2.462 -; at the end of the frame, we go through these tables, storing zeroes to 2.463 -; all these addresses in order to delete the last frame 2.464 - 2.465 -ALIGN &100 2.466 -.olddotaddrlo SKIP numdots 2.467 - 2.468 -ALIGN &100 2.469 -.olddotaddrhi SKIP numdots 2.470 - 2.471 -ALIGN &100 2.472 -.olddotaddry SKIP numdots 2.473 - 2.474 - 2.475 - 2.476 -\ ****************************************************************** 2.477 -\ * Save the code 2.478 -\ ****************************************************************** 2.479 - 2.480 -SAVE "Code", start, end
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/relocdemo.6502 Sun Mar 06 18:19:27 2011 +0100 3.3 @@ -0,0 +1,522 @@ 3.4 +\ ****************************************************************** 3.5 +\ * 3.6 +\ * Relocation demo 3.7 +\ * 3.8 +\ * Simple demonstration of how to write self-relocating code 3.9 +\ * in BeebAsm, using the new 'reload address' feature of SAVE. 3.10 +\ * 3.11 +\ * This uses the 'star globe' demo as a base. 3.12 +\ * 3.13 +\ ****************************************************************** 3.14 + 3.15 + 3.16 +\\ Define addresses 3.17 + 3.18 +NATIVE_ADDR = &300 ; address at which code will run 3.19 +RELOAD_ADDR = &1100 ; address at which code will load 3.20 + 3.21 +OFFSET = RELOAD_ADDR - NATIVE_ADDR 3.22 + 3.23 + 3.24 +\\ Define globals 3.25 + 3.26 +numdots = 160 3.27 +radius = 100 3.28 +timerlength = 64*8*26 3.29 +debugrasters = FALSE 3.30 + 3.31 + 3.32 +\\ Define some zp locations 3.33 + 3.34 +ORG 0 3.35 + 3.36 +.xpos SKIP 1 3.37 +.ypos SKIP 1 3.38 +.colour SKIP 1 3.39 +.write SKIP 2 3.40 +.vsync SKIP 1 3.41 +.angle SKIP 2 3.42 +.speed SKIP 2 3.43 +.counter SKIP 1 3.44 +.temp SKIP 1 3.45 +.behindflag SKIP 1 3.46 + 3.47 + 3.48 +\\ Set start address 3.49 + 3.50 +ORG NATIVE_ADDR 3.51 + 3.52 + 3.53 +\ ****************************************************************** 3.54 +\ * The start of the demo 'proper', after it has been relocated 3.55 +\ ****************************************************************** 3.56 + 3.57 +.START 3.58 + 3.59 + \\ Clear the screen 3.60 + 3.61 + LDX #&40 3.62 + LDA #0 3.63 + TAY 3.64 +.clearloop 3.65 + STA &4000,Y 3.66 + INY 3.67 + BNE clearloop 3.68 + INC clearloop+2 3.69 + DEX 3.70 + BNE clearloop 3.71 + 3.72 + \\ Enable interrupts, ready to start the main loop 3.73 + 3.74 + CLI 3.75 + 3.76 + \\ First we wait for 'vsync' so we are synchronised 3.77 + 3.78 +.initialwait 3.79 + LDA vsync:BEQ initialwait:LDA #0:STA vsync 3.80 + 3.81 + \\ Enable the screen 3.82 + 3.83 + LDA #6:STA &FE00:LDA #32:STA &FE01 3.84 + 3.85 + \\ This is the main loop! 3.86 + 3.87 +.mainloop 3.88 + 3.89 + \\ Plot every dot on the screen 3.90 + 3.91 + LDX #0 3.92 +.plotdotloop 3.93 + STX counter 3.94 + 3.95 + ; setup y pos ready for plot routine 3.96 + 3.97 + LDA doty,X:STA ypos 3.98 + 3.99 + ; get sin index 3.100 + 3.101 + CLC:LDA dotx,X:ADC angle+1:TAY 3.102 + CLC:ADC #64:STA behindflag 3.103 + 3.104 + ; get colour from sin index 3.105 + 3.106 + LDA coltable,Y:STA colour 3.107 + 3.108 + ; perform sin(x) * radius 3.109 + ; discussion of the multiplication method below in the table setup 3.110 + 3.111 + SEC:LDA sintable,Y:STA temp:SBC dotr,X 3.112 + BCS noneg:EOR #&FF:ADC #1:.noneg 3.113 + CPY #128:TAY:BCS negativesine 3.114 + 3.115 + CLC:LDA dotr,X:ADC temp:TAX 3.116 + BCS morethan256:SEC 3.117 + LDA multtab1,X:SBC multtab1,Y:JMP donemult 3.118 + .morethan256 3.119 + LDA multtab2,X:SBC multtab1,Y:JMP donemult 3.120 + 3.121 + .negativesine 3.122 + CLC:LDA dotr,X:ADC temp:TAX 3.123 + BCS morethan256b:SEC 3.124 + LDA multtab1,Y:SBC multtab1,X:JMP donemult 3.125 + .morethan256b 3.126 + LDA multtab1,Y:SBC multtab2,X 3.127 + .donemult 3.128 + 3.129 + CLC:ADC #64:STA xpos 3.130 + 3.131 + ; routine to plot a dot 3.132 + ; also we remember the calculated screen address in the dot tables 3.133 + 3.134 + LDA ypos:LSR A:LSR A:AND #&FE 3.135 + TAX 3.136 + LDA xpos:AND #&FE:ASL A:ASL A 3.137 + STA write 3.138 + LDY counter:STA olddotaddrlo,Y 3.139 + TXA:ADC #&40:STA write+1:STA olddotaddrhi,Y 3.140 + LDA ypos:AND #7:STA olddotaddry,Y:TAY 3.141 + LDA xpos:LSR A:LDA colour:ROL A:TAX 3.142 + LDA colours,X 3.143 + ORA (write),Y 3.144 + STA (write),Y 3.145 + BIT behindflag:BMI behind 3.146 + 3.147 + ; if the dot is in front, we double its size 3.148 + 3.149 + DEY:BPL samescreenrow 3.150 + DEC write+1:DEC write+1:LDY #7:.samescreenrow 3.151 + LDA colours,X 3.152 + ORA (write),Y 3.153 + STA (write),Y 3.154 + .behind 3.155 + 3.156 + ; loop to the next dot 3.157 + 3.158 + LDX counter 3.159 + INX:CPX #numdots 3.160 + BEQ waitforvsync 3.161 + JMP plotdotloop 3.162 + 3.163 + \\ Wait for VSync here 3.164 + 3.165 +.waitforvsync 3.166 + IF debugrasters 3.167 + LDA #&00 + PAL_magenta:STA &FE21 3.168 + ENDIF 3.169 +.waitingforvsync 3.170 + LDA vsync:BEQ waitingforvsync 3.171 + CMP #2:BCS exit ; insist that it runs in a frame! 3.172 + LDA #0:STA vsync 3.173 + 3.174 + \\ Now delete all the old dots. 3.175 + \\ We actually do this when the screen is still rasterising down..! 3.176 + 3.177 + TAX 3.178 +.eraseloop 3.179 + LDY olddotaddrlo,X:STY write 3.180 + LDY olddotaddrhi,X:STY write+1 3.181 + LDY olddotaddry,X 3.182 + STA (write),Y 3.183 + DEY:BPL erasesamerow 3.184 + DEC write+1:DEC write+1:LDY #7:.erasesamerow 3.185 + STA (write),Y 3.186 + INX:CPX #numdots 3.187 + BNE eraseloop 3.188 + 3.189 + IF debugrasters 3.190 + LDA #&00 + PAL_red:STA &FE21 3.191 + ENDIF 3.192 + 3.193 + \\ Add to rotation 3.194 + 3.195 + CLC:LDA angle:ADC speed:STA angle 3.196 + LDA angle+1:ADC speed+1:STA angle+1 3.197 + 3.198 + \\ Check keypresses 3.199 + 3.200 + LDA #66:STA &FE4F:LDA &FE4F:BPL notx 3.201 + CLC:LDA speed:ADC #16:STA speed:BCC notx:INC speed+1:.notx 3.202 + LDA #97:STA &FE4F:LDA &FE4F:BPL notz 3.203 + SEC:LDA speed:SBC #16:STA speed:BCS notz:DEC speed+1:.notz 3.204 + LDA #112:STA &FE4F:LDA &FE4F:BMI exit 3.205 + 3.206 + JMP mainloop 3.207 + 3.208 + \\ Exit - in the least graceful way possible :) 3.209 + 3.210 +.exit 3.211 + JMP (&FFFC) 3.212 + 3.213 + 3.214 + 3.215 +\ ****************************************************************** 3.216 +\ * IRQ handler 3.217 +\ ****************************************************************** 3.218 + 3.219 +.irq 3.220 + LDA &FE4D:AND #2:BNE irqvsync 3.221 +.irqtimer 3.222 + LDA #&40:STA &FE4D:INC vsync 3.223 + IF debugrasters 3.224 + LDA #&00 + PAL_blue:STA &FE21 3.225 + ENDIF 3.226 + LDA &FC 3.227 + RTI 3.228 +.irqvsync 3.229 + STA &FE4D 3.230 + LDA #LO(timerlength):STA &FE44 3.231 + LDA #HI(timerlength):STA &FE45 3.232 + IF debugrasters 3.233 + LDA #&00 + PAL_black:STA &FE21 3.234 + ENDIF 3.235 + LDA &FC 3.236 + RTI 3.237 + 3.238 + 3.239 + 3.240 +\ ****************************************************************** 3.241 +\ * Colour table used by the plot code 3.242 +\ ****************************************************************** 3.243 + 3.244 +.colours 3.245 + EQUB &00, &00 ; black pixels 3.246 + EQUB &02, &01 ; blue pixels 3.247 + EQUB &08, &04 ; red pixels 3.248 + EQUB &0A, &05 ; magenta pixels 3.249 + EQUB &20, &10 ; green pixels 3.250 + EQUB &22, &11 ; cyan pixels 3.251 + EQUB &28, &14 ; yellow pixels 3.252 + EQUB &2A, &15 ; white pixels 3.253 + 3.254 + 3.255 +\ ****************************************************************** 3.256 +\ * sin table 3.257 +\ ****************************************************************** 3.258 + 3.259 +; contains ABS sine values 3.260 +; we don't store the sign as it confuses the multiplication. 3.261 +; we can tell the sign very easily from whether the index is >128 3.262 + 3.263 +ALIGN &100 ; so we don't incur page-crossed penalties 3.264 +.sintable 3.265 +FOR n, 0, 255 3.266 + EQUB ABS(SIN(n/128*PI)) * 255 3.267 +NEXT 3.268 + 3.269 + 3.270 +\ ****************************************************************** 3.271 +\ * colour table 3.272 +\ ****************************************************************** 3.273 + 3.274 +ALIGN &100 3.275 +.coltable 3.276 +FOR n, 0, 255 3.277 + EQUB (SIN(n/128*PI) + 1) / 2.0001 * 7 + 1 3.278 +NEXT 3.279 + 3.280 + 3.281 +\ ****************************************************************** 3.282 +\ * multiplication tables 3.283 +\ ****************************************************************** 3.284 + 3.285 +; This is a very quick way to do multiplies, based on the fact that: 3.286 +; 3.287 +; (a+b)^2 = a^2 + b^2 + 2ab (I) 3.288 +; (a-b)^2 = a^2 + b^2 - 2ab (II) 3.289 +; 3.290 +; (I) minus (II) yields: (a+b)^2 - (a-b)^2 = 4ab 3.291 +; 3.292 +; or, rewritten: ab = f(a+b) - f(a-b), 3.293 +; where f(x) = x^2 / 4 3.294 +; 3.295 +; We build a table of f(x) here with x=0..511, and then can perform 3.296 +; 8-bit * 8-bit by 4 table lookups and a 16-bit subtract. 3.297 +; 3.298 +; In this case, we will discard the low byte of the result, so we 3.299 +; only need the high bytes, and can do just 2 table lookups and a 3.300 +; simple 8-bit subtract. 3.301 + 3.302 +ALIGN &100 3.303 +.multtab1 3.304 +FOR n, 0, 255 3.305 + EQUB HI(n*n DIV 4) 3.306 +NEXT 3.307 +.multtab2 3.308 +FOR n, 256, 511 3.309 + EQUB HI(n*n DIV 4) 3.310 +NEXT 3.311 + 3.312 + 3.313 +\ ****************************************************************** 3.314 +\ * dot tables 3.315 +\ ****************************************************************** 3.316 + 3.317 +; contains the phase of this dot 3.318 + 3.319 +ALIGN &100 3.320 +.dotx 3.321 +FOR n, 0, numdots-1 3.322 + EQUB RND(256) 3.323 +NEXT 3.324 + 3.325 + 3.326 +; contains the y position of the dot 3.327 +; the dots are sorted by y positions, highest on screen first - this means we can do 3.328 +; 'raster chasing'! 3.329 +; the y positions are also biased so there are fewer at the poles, and more at the equator! 3.330 + 3.331 +ALIGN &100 3.332 +.doty 3.333 +FOR n, 0, numdots-1 3.334 + x = (n - numdots/2 + 0.5) / (numdots/2) 3.335 + y = (x - SIN(x*PI) * 0.1) * radius 3.336 + EQUB 128 + y 3.337 +NEXT 3.338 + 3.339 + 3.340 +; contains the radius of the ball at this y position 3.341 + 3.342 +ALIGN &100 3.343 +.dotr 3.344 +FOR n, 0, numdots-1 3.345 + x = (n - numdots/2 + 0.5) / (numdots/2) 3.346 + y = (x - SIN(x*PI) * 0.1) * radius 3.347 + r = SQR(radius*radius - y*y) / 2 3.348 + EQUB r 3.349 +NEXT 3.350 + 3.351 + 3.352 +\ ****************************************************************** 3.353 +\ * This is the end of the main native block of code 3.354 +\ ****************************************************************** 3.355 +.END 3.356 + 3.357 + 3.358 +\ ****************************************************************** 3.359 +\ * The entry point of the demo 3.360 +\ * This relocates the code to its 'real' address, and can also 3.361 +\ * do one-time initialisation, i.e. code we can chuck away afterwards. 3.362 +\ * 3.363 +\ * Since this is the relocation code, it has to go at the very end of 3.364 +\ * the executable. 3.365 +\ 3.366 +\ * This code will be running at its assemble address + OFFSET, 3.367 +\ * so we have to patch up any absolute address references accordingly. 3.368 +\ ****************************************************************** 3.369 + 3.370 +ALIGN &100 3.371 +.RELOC_START 3.372 + 3.373 + \\ Set up hardware state and interrupts 3.374 + 3.375 + SEI 3.376 + LDX #&FF:TXS ; reset stack 3.377 + STX &FE44:STX &FE45 3.378 + LDA #&7F:STA &FE4E ; disable all interrupts 3.379 + STA &FE43 ; set keyboard data direction 3.380 + LDA #&C2:STA &FE4E ; enable VSync and timer interrupt 3.381 + LDA #&0F:STA &FE42 ; set addressable latch for writing 3.382 + LDA #3:STA &FE40 ; keyboard write enable 3.383 + LDA #0:STA &FE4B ; timer 1 one shot mode 3.384 + LDA #LO(irq):STA &204 3.385 + LDA #HI(irq):STA &205 ; set interrupt handler 3.386 + 3.387 + \\ Set up CRTC for MODE 2 3.388 + 3.389 + LDX #13 3.390 +.crtcloop 3.391 + STX &FE00 3.392 + LDA crtcregs + OFFSET,X ; PATCHED ADDRESS 3.393 + STA &FE01 3.394 + DEX 3.395 + BPL crtcloop 3.396 + 3.397 + \\ Set up video ULA for MODE 2 3.398 + 3.399 + LDA #&F4 3.400 + STA &FE20 3.401 + 3.402 + \\ Set up palette for MODE 2 3.403 + 3.404 + LDX #15 3.405 +.palloop 3.406 + LDA paldata + OFFSET,X ; PATCHED ADDRESS 3.407 + STA &FE21 3.408 + ORA #&80 3.409 + STA &FE21 3.410 + DEX 3.411 + BPL palloop 3.412 + 3.413 + \\ Initialise vars 3.414 + 3.415 + LDA #0:STA angle:STA angle+1 3.416 + STA vsync 3.417 + STA speed 3.418 + LDA #1:STA speed+1 3.419 + 3.420 + \\ Relocate 3.421 + 3.422 + LDX #HI(RELOC_START-START) 3.423 + LDY #0 3.424 + .relocloop 3.425 + LDA RELOAD_ADDR,Y 3.426 + STA NATIVE_ADDR,Y 3.427 + INY 3.428 + BNE relocloop 3.429 + INC relocloop+OFFSET+2 ; PATCHED ADDRESS 3.430 + INC relocloop+OFFSET+5 ; PATCHED ADDRESS 3.431 + DEX 3.432 + BNE relocloop 3.433 + 3.434 + JMP START 3.435 + 3.436 + 3.437 +\ ****************************************************************** 3.438 +\ * Values of CRTC regs for MODE 2 3.439 +\ ****************************************************************** 3.440 + 3.441 +.crtcregs 3.442 + EQUB 127 ; R0 horizontal total 3.443 + EQUB 64 ; R1 horizontal displayed - shrunk a little 3.444 + EQUB 91 ; R2 horizontal position 3.445 + EQUB 40 ; R3 sync width 3.446 + EQUB 38 ; R4 vertical total 3.447 + EQUB 0 ; R5 vertical total adjust 3.448 + EQUB 0 ; R6 vertical displayed 3.449 + EQUB 34 ; R7 vertical position 3.450 + EQUB 0 ; R8 interlace 3.451 + EQUB 7 ; R9 scanlines per row 3.452 + EQUB 32 ; R10 cursor start 3.453 + EQUB 8 ; R11 cursor end 3.454 + EQUB HI(&4000/8) ; R12 screen start address, high 3.455 + EQUB LO(&4000/8) ; R13 screen start address, low 3.456 + 3.457 + 3.458 +\ ****************************************************************** 3.459 +\ * Values of palette regs for MODE 2 3.460 +\ ****************************************************************** 3.461 + 3.462 +PAL_black = (0 EOR 7) 3.463 +PAL_blue = (4 EOR 7) 3.464 +PAL_red = (1 EOR 7) 3.465 +PAL_magenta = (5 EOR 7) 3.466 +PAL_green = (2 EOR 7) 3.467 +PAL_cyan = (6 EOR 7) 3.468 +PAL_yellow = (3 EOR 7) 3.469 +PAL_white = (7 EOR 7) 3.470 + 3.471 +.paldata 3.472 + EQUB &00 + PAL_black 3.473 + EQUB &10 + PAL_blue 3.474 + EQUB &20 + PAL_red 3.475 + EQUB &30 + PAL_magenta 3.476 + EQUB &40 + PAL_green 3.477 + EQUB &50 + PAL_cyan 3.478 + EQUB &60 + PAL_yellow 3.479 + EQUB &70 + PAL_white 3.480 + 3.481 + 3.482 + 3.483 + 3.484 +\ ****************************************************************** 3.485 +\ * End address to be saved 3.486 +\ ****************************************************************** 3.487 +.RELOC_END 3.488 + 3.489 + 3.490 +\ ****************************************************************** 3.491 +\ * Save the code, before the following data overlay clears it again 3.492 +\ ****************************************************************** 3.493 + 3.494 +SAVE "Code", START, RELOC_END, RELOC_START+OFFSET, RELOAD_ADDR 3.495 + 3.496 + 3.497 + 3.498 + 3.499 +\ ****************************************************************** 3.500 +\ * Start a new overlay: 3.501 +\ * 3.502 +\ * This is overlapped with the relocation code above, because it 3.503 +\ * will already have been thrown away by the time these tables are 3.504 +\ * used. 3.505 +\ * 3.506 +\ * These tables are filled at run-time, hence we just define their 3.507 +\ * addresses, we don't need to save anything. 3.508 +\ ****************************************************************** 3.509 + 3.510 +CLEAR END, RELOC_END 3.511 +ORG END 3.512 + 3.513 +; these store the screen address of the last dot 3.514 +; at the end of the frame, we go through these tables, storing zeroes to 3.515 +; all these addresses in order to delete the last frame 3.516 + 3.517 +ALIGN &100 3.518 +.olddotaddrlo SKIP numdots 3.519 + 3.520 +ALIGN &100 3.521 +.olddotaddrhi SKIP numdots 3.522 + 3.523 +ALIGN &100 3.524 +.olddotaddry SKIP numdots 3.525 +
4.1 --- a/relocdemo.asm Fri Mar 04 02:01:51 2011 +0000 4.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 4.3 @@ -1,522 +0,0 @@ 4.4 -\ ****************************************************************** 4.5 -\ * 4.6 -\ * Relocation demo 4.7 -\ * 4.8 -\ * Simple demonstration of how to write self-relocating code 4.9 -\ * in BeebAsm, using the new 'reload address' feature of SAVE. 4.10 -\ * 4.11 -\ * This uses the 'star globe' demo as a base. 4.12 -\ * 4.13 -\ ****************************************************************** 4.14 - 4.15 - 4.16 -\\ Define addresses 4.17 - 4.18 -NATIVE_ADDR = &300 ; address at which code will run 4.19 -RELOAD_ADDR = &1100 ; address at which code will load 4.20 - 4.21 -OFFSET = RELOAD_ADDR - NATIVE_ADDR 4.22 - 4.23 - 4.24 -\\ Define globals 4.25 - 4.26 -numdots = 160 4.27 -radius = 100 4.28 -timerlength = 64*8*26 4.29 -debugrasters = FALSE 4.30 - 4.31 - 4.32 -\\ Define some zp locations 4.33 - 4.34 -ORG 0 4.35 - 4.36 -.xpos SKIP 1 4.37 -.ypos SKIP 1 4.38 -.colour SKIP 1 4.39 -.write SKIP 2 4.40 -.vsync SKIP 1 4.41 -.angle SKIP 2 4.42 -.speed SKIP 2 4.43 -.counter SKIP 1 4.44 -.temp SKIP 1 4.45 -.behindflag SKIP 1 4.46 - 4.47 - 4.48 -\\ Set start address 4.49 - 4.50 -ORG NATIVE_ADDR 4.51 - 4.52 - 4.53 -\ ****************************************************************** 4.54 -\ * The start of the demo 'proper', after it has been relocated 4.55 -\ ****************************************************************** 4.56 - 4.57 -.START 4.58 - 4.59 - \\ Clear the screen 4.60 - 4.61 - LDX #&40 4.62 - LDA #0 4.63 - TAY 4.64 -.clearloop 4.65 - STA &4000,Y 4.66 - INY 4.67 - BNE clearloop 4.68 - INC clearloop+2 4.69 - DEX 4.70 - BNE clearloop 4.71 - 4.72 - \\ Enable interrupts, ready to start the main loop 4.73 - 4.74 - CLI 4.75 - 4.76 - \\ First we wait for 'vsync' so we are synchronised 4.77 - 4.78 -.initialwait 4.79 - LDA vsync:BEQ initialwait:LDA #0:STA vsync 4.80 - 4.81 - \\ Enable the screen 4.82 - 4.83 - LDA #6:STA &FE00:LDA #32:STA &FE01 4.84 - 4.85 - \\ This is the main loop! 4.86 - 4.87 -.mainloop 4.88 - 4.89 - \\ Plot every dot on the screen 4.90 - 4.91 - LDX #0 4.92 -.plotdotloop 4.93 - STX counter 4.94 - 4.95 - ; setup y pos ready for plot routine 4.96 - 4.97 - LDA doty,X:STA ypos 4.98 - 4.99 - ; get sin index 4.100 - 4.101 - CLC:LDA dotx,X:ADC angle+1:TAY 4.102 - CLC:ADC #64:STA behindflag 4.103 - 4.104 - ; get colour from sin index 4.105 - 4.106 - LDA coltable,Y:STA colour 4.107 - 4.108 - ; perform sin(x) * radius 4.109 - ; discussion of the multiplication method below in the table setup 4.110 - 4.111 - SEC:LDA sintable,Y:STA temp:SBC dotr,X 4.112 - BCS noneg:EOR #&FF:ADC #1:.noneg 4.113 - CPY #128:TAY:BCS negativesine 4.114 - 4.115 - CLC:LDA dotr,X:ADC temp:TAX 4.116 - BCS morethan256:SEC 4.117 - LDA multtab1,X:SBC multtab1,Y:JMP donemult 4.118 - .morethan256 4.119 - LDA multtab2,X:SBC multtab1,Y:JMP donemult 4.120 - 4.121 - .negativesine 4.122 - CLC:LDA dotr,X:ADC temp:TAX 4.123 - BCS morethan256b:SEC 4.124 - LDA multtab1,Y:SBC multtab1,X:JMP donemult 4.125 - .morethan256b 4.126 - LDA multtab1,Y:SBC multtab2,X 4.127 - .donemult 4.128 - 4.129 - CLC:ADC #64:STA xpos 4.130 - 4.131 - ; routine to plot a dot 4.132 - ; also we remember the calculated screen address in the dot tables 4.133 - 4.134 - LDA ypos:LSR A:LSR A:AND #&FE 4.135 - TAX 4.136 - LDA xpos:AND #&FE:ASL A:ASL A 4.137 - STA write 4.138 - LDY counter:STA olddotaddrlo,Y 4.139 - TXA:ADC #&40:STA write+1:STA olddotaddrhi,Y 4.140 - LDA ypos:AND #7:STA olddotaddry,Y:TAY 4.141 - LDA xpos:LSR A:LDA colour:ROL A:TAX 4.142 - LDA colours,X 4.143 - ORA (write),Y 4.144 - STA (write),Y 4.145 - BIT behindflag:BMI behind 4.146 - 4.147 - ; if the dot is in front, we double its size 4.148 - 4.149 - DEY:BPL samescreenrow 4.150 - DEC write+1:DEC write+1:LDY #7:.samescreenrow 4.151 - LDA colours,X 4.152 - ORA (write),Y 4.153 - STA (write),Y 4.154 - .behind 4.155 - 4.156 - ; loop to the next dot 4.157 - 4.158 - LDX counter 4.159 - INX:CPX #numdots 4.160 - BEQ waitforvsync 4.161 - JMP plotdotloop 4.162 - 4.163 - \\ Wait for VSync here 4.164 - 4.165 -.waitforvsync 4.166 - IF debugrasters 4.167 - LDA #&00 + PAL_magenta:STA &FE21 4.168 - ENDIF 4.169 -.waitingforvsync 4.170 - LDA vsync:BEQ waitingforvsync 4.171 - CMP #2:BCS exit ; insist that it runs in a frame! 4.172 - LDA #0:STA vsync 4.173 - 4.174 - \\ Now delete all the old dots. 4.175 - \\ We actually do this when the screen is still rasterising down..! 4.176 - 4.177 - TAX 4.178 -.eraseloop 4.179 - LDY olddotaddrlo,X:STY write 4.180 - LDY olddotaddrhi,X:STY write+1 4.181 - LDY olddotaddry,X 4.182 - STA (write),Y 4.183 - DEY:BPL erasesamerow 4.184 - DEC write+1:DEC write+1:LDY #7:.erasesamerow 4.185 - STA (write),Y 4.186 - INX:CPX #numdots 4.187 - BNE eraseloop 4.188 - 4.189 - IF debugrasters 4.190 - LDA #&00 + PAL_red:STA &FE21 4.191 - ENDIF 4.192 - 4.193 - \\ Add to rotation 4.194 - 4.195 - CLC:LDA angle:ADC speed:STA angle 4.196 - LDA angle+1:ADC speed+1:STA angle+1 4.197 - 4.198 - \\ Check keypresses 4.199 - 4.200 - LDA #66:STA &FE4F:LDA &FE4F:BPL notx 4.201 - CLC:LDA speed:ADC #16:STA speed:BCC notx:INC speed+1:.notx 4.202 - LDA #97:STA &FE4F:LDA &FE4F:BPL notz 4.203 - SEC:LDA speed:SBC #16:STA speed:BCS notz:DEC speed+1:.notz 4.204 - LDA #112:STA &FE4F:LDA &FE4F:BMI exit 4.205 - 4.206 - JMP mainloop 4.207 - 4.208 - \\ Exit - in the least graceful way possible :) 4.209 - 4.210 -.exit 4.211 - JMP (&FFFC) 4.212 - 4.213 - 4.214 - 4.215 -\ ****************************************************************** 4.216 -\ * IRQ handler 4.217 -\ ****************************************************************** 4.218 - 4.219 -.irq 4.220 - LDA &FE4D:AND #2:BNE irqvsync 4.221 -.irqtimer 4.222 - LDA #&40:STA &FE4D:INC vsync 4.223 - IF debugrasters 4.224 - LDA #&00 + PAL_blue:STA &FE21 4.225 - ENDIF 4.226 - LDA &FC 4.227 - RTI 4.228 -.irqvsync 4.229 - STA &FE4D 4.230 - LDA #LO(timerlength):STA &FE44 4.231 - LDA #HI(timerlength):STA &FE45 4.232 - IF debugrasters 4.233 - LDA #&00 + PAL_black:STA &FE21 4.234 - ENDIF 4.235 - LDA &FC 4.236 - RTI 4.237 - 4.238 - 4.239 - 4.240 -\ ****************************************************************** 4.241 -\ * Colour table used by the plot code 4.242 -\ ****************************************************************** 4.243 - 4.244 -.colours 4.245 - EQUB &00, &00 ; black pixels 4.246 - EQUB &02, &01 ; blue pixels 4.247 - EQUB &08, &04 ; red pixels 4.248 - EQUB &0A, &05 ; magenta pixels 4.249 - EQUB &20, &10 ; green pixels 4.250 - EQUB &22, &11 ; cyan pixels 4.251 - EQUB &28, &14 ; yellow pixels 4.252 - EQUB &2A, &15 ; white pixels 4.253 - 4.254 - 4.255 -\ ****************************************************************** 4.256 -\ * sin table 4.257 -\ ****************************************************************** 4.258 - 4.259 -; contains ABS sine values 4.260 -; we don't store the sign as it confuses the multiplication. 4.261 -; we can tell the sign very easily from whether the index is >128 4.262 - 4.263 -ALIGN &100 ; so we don't incur page-crossed penalties 4.264 -.sintable 4.265 -FOR n, 0, 255 4.266 - EQUB ABS(SIN(n/128*PI)) * 255 4.267 -NEXT 4.268 - 4.269 - 4.270 -\ ****************************************************************** 4.271 -\ * colour table 4.272 -\ ****************************************************************** 4.273 - 4.274 -ALIGN &100 4.275 -.coltable 4.276 -FOR n, 0, 255 4.277 - EQUB (SIN(n/128*PI) + 1) / 2.0001 * 7 + 1 4.278 -NEXT 4.279 - 4.280 - 4.281 -\ ****************************************************************** 4.282 -\ * multiplication tables 4.283 -\ ****************************************************************** 4.284 - 4.285 -; This is a very quick way to do multiplies, based on the fact that: 4.286 -; 4.287 -; (a+b)^2 = a^2 + b^2 + 2ab (I) 4.288 -; (a-b)^2 = a^2 + b^2 - 2ab (II) 4.289 -; 4.290 -; (I) minus (II) yields: (a+b)^2 - (a-b)^2 = 4ab 4.291 -; 4.292 -; or, rewritten: ab = f(a+b) - f(a-b), 4.293 -; where f(x) = x^2 / 4 4.294 -; 4.295 -; We build a table of f(x) here with x=0..511, and then can perform 4.296 -; 8-bit * 8-bit by 4 table lookups and a 16-bit subtract. 4.297 -; 4.298 -; In this case, we will discard the low byte of the result, so we 4.299 -; only need the high bytes, and can do just 2 table lookups and a 4.300 -; simple 8-bit subtract. 4.301 - 4.302 -ALIGN &100 4.303 -.multtab1 4.304 -FOR n, 0, 255 4.305 - EQUB HI(n*n DIV 4) 4.306 -NEXT 4.307 -.multtab2 4.308 -FOR n, 256, 511 4.309 - EQUB HI(n*n DIV 4) 4.310 -NEXT 4.311 - 4.312 - 4.313 -\ ****************************************************************** 4.314 -\ * dot tables 4.315 -\ ****************************************************************** 4.316 - 4.317 -; contains the phase of this dot 4.318 - 4.319 -ALIGN &100 4.320 -.dotx 4.321 -FOR n, 0, numdots-1 4.322 - EQUB RND(256) 4.323 -NEXT 4.324 - 4.325 - 4.326 -; contains the y position of the dot 4.327 -; the dots are sorted by y positions, highest on screen first - this means we can do 4.328 -; 'raster chasing'! 4.329 -; the y positions are also biased so there are fewer at the poles, and more at the equator! 4.330 - 4.331 -ALIGN &100 4.332 -.doty 4.333 -FOR n, 0, numdots-1 4.334 - x = (n - numdots/2 + 0.5) / (numdots/2) 4.335 - y = (x - SIN(x*PI) * 0.1) * radius 4.336 - EQUB 128 + y 4.337 -NEXT 4.338 - 4.339 - 4.340 -; contains the radius of the ball at this y position 4.341 - 4.342 -ALIGN &100 4.343 -.dotr 4.344 -FOR n, 0, numdots-1 4.345 - x = (n - numdots/2 + 0.5) / (numdots/2) 4.346 - y = (x - SIN(x*PI) * 0.1) * radius 4.347 - r = SQR(radius*radius - y*y) / 2 4.348 - EQUB r 4.349 -NEXT 4.350 - 4.351 - 4.352 -\ ****************************************************************** 4.353 -\ * This is the end of the main native block of code 4.354 -\ ****************************************************************** 4.355 -.END 4.356 - 4.357 - 4.358 -\ ****************************************************************** 4.359 -\ * The entry point of the demo 4.360 -\ * This relocates the code to its 'real' address, and can also 4.361 -\ * do one-time initialisation, i.e. code we can chuck away afterwards. 4.362 -\ * 4.363 -\ * Since this is the relocation code, it has to go at the very end of 4.364 -\ * the executable. 4.365 -\ 4.366 -\ * This code will be running at its assemble address + OFFSET, 4.367 -\ * so we have to patch up any absolute address references accordingly. 4.368 -\ ****************************************************************** 4.369 - 4.370 -ALIGN &100 4.371 -.RELOC_START 4.372 - 4.373 - \\ Set up hardware state and interrupts 4.374 - 4.375 - SEI 4.376 - LDX #&FF:TXS ; reset stack 4.377 - STX &FE44:STX &FE45 4.378 - LDA #&7F:STA &FE4E ; disable all interrupts 4.379 - STA &FE43 ; set keyboard data direction 4.380 - LDA #&C2:STA &FE4E ; enable VSync and timer interrupt 4.381 - LDA #&0F:STA &FE42 ; set addressable latch for writing 4.382 - LDA #3:STA &FE40 ; keyboard write enable 4.383 - LDA #0:STA &FE4B ; timer 1 one shot mode 4.384 - LDA #LO(irq):STA &204 4.385 - LDA #HI(irq):STA &205 ; set interrupt handler 4.386 - 4.387 - \\ Set up CRTC for MODE 2 4.388 - 4.389 - LDX #13 4.390 -.crtcloop 4.391 - STX &FE00 4.392 - LDA crtcregs + OFFSET,X ; PATCHED ADDRESS 4.393 - STA &FE01 4.394 - DEX 4.395 - BPL crtcloop 4.396 - 4.397 - \\ Set up video ULA for MODE 2 4.398 - 4.399 - LDA #&F4 4.400 - STA &FE20 4.401 - 4.402 - \\ Set up palette for MODE 2 4.403 - 4.404 - LDX #15 4.405 -.palloop 4.406 - LDA paldata + OFFSET,X ; PATCHED ADDRESS 4.407 - STA &FE21 4.408 - ORA #&80 4.409 - STA &FE21 4.410 - DEX 4.411 - BPL palloop 4.412 - 4.413 - \\ Initialise vars 4.414 - 4.415 - LDA #0:STA angle:STA angle+1 4.416 - STA vsync 4.417 - STA speed 4.418 - LDA #1:STA speed+1 4.419 - 4.420 - \\ Relocate 4.421 - 4.422 - LDX #HI(RELOC_START-START) 4.423 - LDY #0 4.424 - .relocloop 4.425 - LDA RELOAD_ADDR,Y 4.426 - STA NATIVE_ADDR,Y 4.427 - INY 4.428 - BNE relocloop 4.429 - INC relocloop+OFFSET+2 ; PATCHED ADDRESS 4.430 - INC relocloop+OFFSET+5 ; PATCHED ADDRESS 4.431 - DEX 4.432 - BNE relocloop 4.433 - 4.434 - JMP START 4.435 - 4.436 - 4.437 -\ ****************************************************************** 4.438 -\ * Values of CRTC regs for MODE 2 4.439 -\ ****************************************************************** 4.440 - 4.441 -.crtcregs 4.442 - EQUB 127 ; R0 horizontal total 4.443 - EQUB 64 ; R1 horizontal displayed - shrunk a little 4.444 - EQUB 91 ; R2 horizontal position 4.445 - EQUB 40 ; R3 sync width 4.446 - EQUB 38 ; R4 vertical total 4.447 - EQUB 0 ; R5 vertical total adjust 4.448 - EQUB 0 ; R6 vertical displayed 4.449 - EQUB 34 ; R7 vertical position 4.450 - EQUB 0 ; R8 interlace 4.451 - EQUB 7 ; R9 scanlines per row 4.452 - EQUB 32 ; R10 cursor start 4.453 - EQUB 8 ; R11 cursor end 4.454 - EQUB HI(&4000/8) ; R12 screen start address, high 4.455 - EQUB LO(&4000/8) ; R13 screen start address, low 4.456 - 4.457 - 4.458 -\ ****************************************************************** 4.459 -\ * Values of palette regs for MODE 2 4.460 -\ ****************************************************************** 4.461 - 4.462 -PAL_black = (0 EOR 7) 4.463 -PAL_blue = (4 EOR 7) 4.464 -PAL_red = (1 EOR 7) 4.465 -PAL_magenta = (5 EOR 7) 4.466 -PAL_green = (2 EOR 7) 4.467 -PAL_cyan = (6 EOR 7) 4.468 -PAL_yellow = (3 EOR 7) 4.469 -PAL_white = (7 EOR 7) 4.470 - 4.471 -.paldata 4.472 - EQUB &00 + PAL_black 4.473 - EQUB &10 + PAL_blue 4.474 - EQUB &20 + PAL_red 4.475 - EQUB &30 + PAL_magenta 4.476 - EQUB &40 + PAL_green 4.477 - EQUB &50 + PAL_cyan 4.478 - EQUB &60 + PAL_yellow 4.479 - EQUB &70 + PAL_white 4.480 - 4.481 - 4.482 - 4.483 - 4.484 -\ ****************************************************************** 4.485 -\ * End address to be saved 4.486 -\ ****************************************************************** 4.487 -.RELOC_END 4.488 - 4.489 - 4.490 -\ ****************************************************************** 4.491 -\ * Save the code, before the following data overlay clears it again 4.492 -\ ****************************************************************** 4.493 - 4.494 -SAVE "Code", START, RELOC_END, RELOC_START+OFFSET, RELOAD_ADDR 4.495 - 4.496 - 4.497 - 4.498 - 4.499 -\ ****************************************************************** 4.500 -\ * Start a new overlay: 4.501 -\ * 4.502 -\ * This is overlapped with the relocation code above, because it 4.503 -\ * will already have been thrown away by the time these tables are 4.504 -\ * used. 4.505 -\ * 4.506 -\ * These tables are filled at run-time, hence we just define their 4.507 -\ * addresses, we don't need to save anything. 4.508 -\ ****************************************************************** 4.509 - 4.510 -CLEAR END, RELOC_END 4.511 -ORG END 4.512 - 4.513 -; these store the screen address of the last dot 4.514 -; at the end of the frame, we go through these tables, storing zeroes to 4.515 -; all these addresses in order to delete the last frame 4.516 - 4.517 -ALIGN &100 4.518 -.olddotaddrlo SKIP numdots 4.519 - 4.520 -ALIGN &100 4.521 -.olddotaddrhi SKIP numdots 4.522 - 4.523 -ALIGN &100 4.524 -.olddotaddry SKIP numdots 4.525 -
5.1 --- a/src/Makefile Fri Mar 04 02:01:51 2011 +0000 5.2 +++ b/src/Makefile Sun Mar 06 18:19:27 2011 +0100 5.3 @@ -51,7 +51,8 @@ 5.4 5.5 # Parameters to the executable 5.6 5.7 -PARAMS := -i ../demo.asm -do ../demo.ssd -boot Code 5.8 +#PARAMS := -i ../demo.6502 -do ../demo.ssd -boot Code 5.9 +PARAMS := -i ../test.6502 -v 5.10 5.11 5.12
6.1 --- a/src/Makefile.inc Fri Mar 04 02:01:51 2011 +0000 6.2 +++ b/src/Makefile.inc Sun Mar 06 18:19:27 2011 +0100 6.3 @@ -192,7 +192,7 @@ 6.4 code: deps objs $(TARGET) 6.5 6.6 run: 6.7 - $(ECHO) Running ... $(TARGET)\n 6.8 + $(ECHO) Running ... $(TARGET) 6.9 $(VB)$(TARGET) $(PARAMS) 6.10 6.11
7.1 --- a/src/VS2010/BeebAsm.vcxproj Fri Mar 04 02:01:51 2011 +0000 7.2 +++ b/src/VS2010/BeebAsm.vcxproj Sun Mar 06 18:19:27 2011 +0100 7.3 @@ -82,6 +82,7 @@ 7.4 <ClCompile Include="..\expression.cpp" /> 7.5 <ClCompile Include="..\globaldata.cpp" /> 7.6 <ClCompile Include="..\lineparser.cpp" /> 7.7 + <ClCompile Include="..\macro.cpp" /> 7.8 <ClCompile Include="..\main.cpp" /> 7.9 <ClCompile Include="..\objectcode.cpp" /> 7.10 <ClCompile Include="..\sourcefile.cpp" /> 7.11 @@ -94,12 +95,12 @@ 7.12 <ClInclude Include="..\discimage.h" /> 7.13 <ClInclude Include="..\globaldata.h" /> 7.14 <ClInclude Include="..\lineparser.h" /> 7.15 + <ClInclude Include="..\macro.h" /> 7.16 <ClInclude Include="..\main.h" /> 7.17 <ClInclude Include="..\objectcode.h" /> 7.18 <ClInclude Include="..\sourcefile.h" /> 7.19 <ClInclude Include="..\stringutils.h" /> 7.20 <ClInclude Include="..\symboltable.h" /> 7.21 - <ClInclude Include="..\tokens.h" /> 7.22 </ItemGroup> 7.23 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> 7.24 <ImportGroup Label="ExtensionTargets">
8.1 --- a/src/VS2010/BeebAsm.vcxproj.filters Fri Mar 04 02:01:51 2011 +0000 8.2 +++ b/src/VS2010/BeebAsm.vcxproj.filters Sun Mar 06 18:19:27 2011 +0100 8.3 @@ -54,6 +54,9 @@ 8.4 <ClCompile Include="..\BASIC.cpp"> 8.5 <Filter>Source Files</Filter> 8.6 </ClCompile> 8.7 + <ClCompile Include="..\macro.cpp"> 8.8 + <Filter>Source Files</Filter> 8.9 + </ClCompile> 8.10 </ItemGroup> 8.11 <ItemGroup> 8.12 <ClInclude Include="..\asmexception.h"> 8.13 @@ -83,10 +86,10 @@ 8.14 <ClInclude Include="..\symboltable.h"> 8.15 <Filter>Header Files</Filter> 8.16 </ClInclude> 8.17 - <ClInclude Include="..\tokens.h"> 8.18 + <ClInclude Include="..\BASIC.h"> 8.19 <Filter>Header Files</Filter> 8.20 </ClInclude> 8.21 - <ClInclude Include="..\BASIC.h"> 8.22 + <ClInclude Include="..\macro.h"> 8.23 <Filter>Header Files</Filter> 8.24 </ClInclude> 8.25 </ItemGroup>
9.1 --- a/src/asmexception.h Fri Mar 04 02:01:51 2011 +0000 9.2 +++ b/src/asmexception.h Sun Mar 06 18:19:27 2011 +0100 9.3 @@ -199,8 +199,12 @@ 9.4 DEFINE_SYNTAX_EXCEPTION( NoIndexedX, "X indexed mode does not exist for this instruction." ); 9.5 DEFINE_SYNTAX_EXCEPTION( NoIndexedY, "Y indexed mode does not exist for this instruction." ); 9.6 DEFINE_SYNTAX_EXCEPTION( LabelAlreadyDefined, "Symbol already defined." ); 9.7 -DEFINE_SYNTAX_EXCEPTION( InvalidSymbolName, "Invalid symbol name; must start with a letter and contain only numbers and underscore." ); 9.8 +DEFINE_SYNTAX_EXCEPTION( InvalidSymbolName, "Invalid symbol name; must start with a letter and contain only letters, numbers and underscore." ); 9.9 DEFINE_SYNTAX_EXCEPTION( SecondPassProblem, "Fatal error: the second assembler pass has generated different code to the first." ); 9.10 +DEFINE_SYNTAX_EXCEPTION( InvalidMacroName, "Invalid macro name; must start with a letter and contain only letters, numbers and underscore." ); 9.11 +DEFINE_SYNTAX_EXCEPTION( NoNestedMacros, "Cannot define one macro inside another." ); 9.12 +DEFINE_SYNTAX_EXCEPTION( EndMacroUnexpected, "ENDMACRO encountered without a matching MACRO directive." ); 9.13 +DEFINE_SYNTAX_EXCEPTION( DuplicateMacroName, "Macro name already defined." ); 9.14 9.15 // meta-language parsing exceptions 9.16 DEFINE_SYNTAX_EXCEPTION( NextWithoutFor, "NEXT without FOR." );
10.1 --- a/src/commands.cpp Fri Mar 04 02:01:51 2011 +0000 10.2 +++ b/src/commands.cpp Sun Mar 06 18:19:27 2011 +0100 10.3 @@ -70,7 +70,9 @@ 10.4 { "}", &LineParser::HandleCloseBrace, 0 }, 10.5 { "MAPCHAR", &LineParser::HandleMapChar, 0 }, 10.6 { "PUTFILE", &LineParser::HandlePutFile, 0 }, 10.7 - { "PUTBASIC", &LineParser::HandlePutBasic, 0 } 10.8 + { "PUTBASIC", &LineParser::HandlePutBasic, 0 }, 10.9 + { "MACRO", &LineParser::HandleMacro, &SourceFile::StartMacro }, 10.10 + { "ENDMACRO", &LineParser::HandleEndMacro, &SourceFile::EndMacro } 10.11 }; 10.12 10.13 10.14 @@ -568,7 +570,7 @@ 10.15 { 10.16 string filename( m_line.substr( m_column + 1, endQuotePos - m_column - 1 ) ); 10.17 10.18 - if ( GlobalData::Instance().IsFirstPass() ) 10.19 + if ( GlobalData::Instance().ShouldOutputAsm() ) 10.20 { 10.21 cerr << "Including file " << filename << endl; 10.22 } 10.23 @@ -1049,10 +1051,10 @@ 10.24 10.25 // expect no more 10.26 10.27 - if ( AdvanceAndCheckEndOfStatement() ) 10.28 + if ( m_line[ m_column ] == ',' ) 10.29 { 10.30 - // found something else - wrong! 10.31 - throw AsmException_SyntaxError_InvalidCharacter( m_line, m_column ); 10.32 + // Unexpected comma (remembering that an expression can validly end with a comma) 10.33 + throw AsmException_SyntaxError_UnexpectedComma( m_line, m_column ); 10.34 } 10.35 10.36 // OK - do it 10.37 @@ -1535,8 +1537,6 @@ 10.38 inputFile.read( buffer, fileSize ); 10.39 inputFile.close(); 10.40 10.41 - cout << "Read file " << hostFilename << ": size " << fileSize << " bytes" << ": " << hex << start << " " << exec << endl; 10.42 - 10.43 if ( GlobalData::Instance().UsesDiscImage() ) 10.44 { 10.45 // disc image version of the save 10.46 @@ -1656,3 +1656,96 @@ 10.47 10.48 } 10.49 10.50 + 10.51 +/*************************************************************************************************/ 10.52 +/** 10.53 + LineParser::HandleMacro() 10.54 +*/ 10.55 +/*************************************************************************************************/ 10.56 +void LineParser::HandleMacro() 10.57 +{ 10.58 + if ( !AdvanceAndCheckEndOfStatement() ) 10.59 + { 10.60 + throw AsmException_SyntaxError_EmptyExpression( m_line, m_column ); 10.61 + } 10.62 + 10.63 + string macroName; 10.64 + 10.65 + if ( isalpha( m_line[ m_column ] ) || m_line[ m_column ] == '_' ) 10.66 + { 10.67 + macroName = GetSymbolName(); 10.68 + 10.69 + if ( GlobalData::Instance().IsFirstPass() ) 10.70 + { 10.71 + if ( MacroTable::Instance().Exists( macroName ) ) 10.72 + { 10.73 + throw AsmException_SyntaxError_DuplicateMacroName( m_line, m_column ); 10.74 + } 10.75 + 10.76 + m_sourceFile->GetCurrentMacro()->SetName( macroName ); 10.77 + cout << "MACRO '" << macroName << "'" << endl; 10.78 + } 10.79 + } 10.80 + else 10.81 + { 10.82 + throw AsmException_SyntaxError_InvalidMacroName( m_line, m_column ); 10.83 + } 10.84 + 10.85 + bool bExpectComma = false; 10.86 + bool bHasParameters = false; 10.87 + 10.88 + while ( AdvanceAndCheckEndOfStatement() ) 10.89 + { 10.90 + if ( bExpectComma ) 10.91 + { 10.92 + if ( m_line[ m_column ] == ',' ) 10.93 + { 10.94 + m_column++; 10.95 + bExpectComma = false; 10.96 + } 10.97 + else 10.98 + { 10.99 + throw AsmException_SyntaxError_MissingComma( m_line, m_column ); 10.100 + } 10.101 + } 10.102 + else if ( isalpha( m_line[ m_column ] ) || m_line[ m_column ] == '_' ) 10.103 + { 10.104 + string param = GetSymbolName(); 10.105 + 10.106 + if ( GlobalData::Instance().IsFirstPass() ) 10.107 + { 10.108 + m_sourceFile->GetCurrentMacro()->AddParameter( param ); 10.109 + cout << " param: '" << param << "'" << endl; 10.110 + } 10.111 + bExpectComma = true; 10.112 + bHasParameters = true; 10.113 + } 10.114 + else 10.115 + { 10.116 + throw AsmException_SyntaxError_InvalidSymbolName( m_line, m_column ); 10.117 + } 10.118 + } 10.119 + 10.120 + if ( bHasParameters && !bExpectComma ) 10.121 + { 10.122 + throw AsmException_SyntaxError_UnexpectedComma( m_line, m_column - 1 ); 10.123 + } 10.124 + 10.125 + m_sourceFile->SetCurrentIfCondition(false); 10.126 +} 10.127 + 10.128 + 10.129 +/*************************************************************************************************/ 10.130 +/** 10.131 + LineParser::HandleEndMacro() 10.132 +*/ 10.133 +/*************************************************************************************************/ 10.134 +void LineParser::HandleEndMacro() 10.135 +{ 10.136 + if ( AdvanceAndCheckEndOfStatement() ) 10.137 + { 10.138 + // found something 10.139 + throw AsmException_SyntaxError_InvalidCharacter( m_line, m_column ); 10.140 + } 10.141 +} 10.142 +
11.1 --- a/src/lineparser.cpp Fri Mar 04 02:01:51 2011 +0000 11.2 +++ b/src/lineparser.cpp Sun Mar 06 18:19:27 2011 +0100 11.3 @@ -22,6 +22,7 @@ 11.4 */ 11.5 /*************************************************************************************************/ 11.6 11.7 +#include <iostream> 11.8 #include "lineparser.h" 11.9 #include "asmexception.h" 11.10 #include "stringutils.h" 11.11 @@ -130,6 +131,7 @@ 11.12 { 11.13 m_column = oldColumn; 11.14 SkipStatement(); 11.15 + 11.16 continue; 11.17 } 11.18 11.19 @@ -210,35 +212,49 @@ 11.20 bool bInQuotes = false; 11.21 bool bInSingleQuotes = false; 11.22 11.23 - while ( m_column < m_line.length() && ( bInQuotes || bInSingleQuotes || MoveToNextAtom( ":;\\" ) ) ) 11.24 + int oldColumn = m_column; 11.25 + 11.26 + if ( m_line[ m_column ] == '{' || m_line[ m_column ] == '}' || m_line[ m_column ] == ':' ) 11.27 { 11.28 - if ( m_line[ m_column ] == '\"' && !bInSingleQuotes ) 11.29 - { 11.30 - bInQuotes = !bInQuotes; 11.31 - } 11.32 - else if ( m_line[ m_column ] == '\'' ) 11.33 - { 11.34 - if ( bInSingleQuotes ) 11.35 - { 11.36 - bInSingleQuotes = false; 11.37 - } 11.38 - else if ( m_line[ m_column + 2 ] == '\'' && !bInQuotes ) 11.39 - { 11.40 - bInSingleQuotes = true; 11.41 - m_column++; 11.42 - } 11.43 - } 11.44 - 11.45 m_column++; 11.46 } 11.47 - 11.48 - if ( m_line[ m_column ] == '\\' || m_line[ m_column ] == ';' ) 11.49 + else if ( m_line[ m_column ] == '\\' || m_line[ m_column ] == ';' ) 11.50 { 11.51 m_column = m_line.length(); 11.52 } 11.53 - else if ( m_line[ m_column ] == ':' ) 11.54 + else 11.55 { 11.56 - m_column++; 11.57 + while ( m_column < m_line.length() && ( bInQuotes || bInSingleQuotes || MoveToNextAtom( ":;\\{}" ) ) ) 11.58 + { 11.59 + if ( m_line[ m_column ] == '\"' && !bInSingleQuotes ) 11.60 + { 11.61 + bInQuotes = !bInQuotes; 11.62 + } 11.63 + else if ( m_line[ m_column ] == '\'' ) 11.64 + { 11.65 + if ( bInSingleQuotes ) 11.66 + { 11.67 + bInSingleQuotes = false; 11.68 + } 11.69 + else if ( m_line[ m_column + 2 ] == '\'' && !bInQuotes ) 11.70 + { 11.71 + bInSingleQuotes = true; 11.72 + m_column++; 11.73 + } 11.74 + } 11.75 + 11.76 + m_column++; 11.77 + } 11.78 + } 11.79 + 11.80 + if ( m_sourceFile->GetCurrentMacro() != NULL && 11.81 + m_line[ oldColumn ] != ':' && 11.82 + m_line[ oldColumn ] != '\\' && 11.83 + m_line[ oldColumn ] != ';' ) 11.84 + { 11.85 + string command = m_line.substr( oldColumn, m_column - oldColumn ); 11.86 + m_sourceFile->GetCurrentMacro()->AddLine( command ); 11.87 + cout << " '" << command << "'" << endl; 11.88 } 11.89 } 11.90 11.91 @@ -378,7 +394,7 @@ 11.92 /*************************************************************************************************/ 11.93 bool LineParser::AdvanceAndCheckEndOfStatement() 11.94 { 11.95 - return MoveToNextAtom( ";:\\" ); 11.96 + return MoveToNextAtom( ";:\\{}" ); 11.97 } 11.98 11.99 11.100 @@ -398,7 +414,7 @@ 11.101 /*************************************************************************************************/ 11.102 bool LineParser::AdvanceAndCheckEndOfSubStatement() 11.103 { 11.104 - return MoveToNextAtom( ";:\\," ); 11.105 + return MoveToNextAtom( ";:\\,{}" ); 11.106 } 11.107 11.108
12.1 --- a/src/lineparser.h Fri Mar 04 02:01:51 2011 +0000 12.2 +++ b/src/lineparser.h Sun Mar 06 18:19:27 2011 +0100 12.3 @@ -46,7 +46,7 @@ 12.4 private: 12.5 12.6 typedef void ( LineParser::*TokenHandler )(); 12.7 - typedef void ( SourceFile::*DirectiveHandler )( std::string line, int column ); 12.8 + typedef void ( SourceFile::*DirectiveHandler )( const std::string& line, int column ); 12.9 12.10 struct Token 12.11 { 12.12 @@ -150,6 +150,8 @@ 12.13 void HandleMapChar(); 12.14 void HandlePutFile(); 12.15 void HandlePutBasic(); 12.16 + void HandleMacro(); 12.17 + void HandleEndMacro(); 12.18 12.19 // expression evaluating methods 12.20
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 13.2 +++ b/src/macro.cpp Sun Mar 06 18:19:27 2011 +0100 13.3 @@ -0,0 +1,143 @@ 13.4 +/*************************************************************************************************/ 13.5 +/** 13.6 + macro.cpp 13.7 + 13.8 + 13.9 + Copyright (C) Rich Talbot-Watkins 2007, 2008 13.10 + 13.11 + This file is part of BeebAsm. 13.12 + 13.13 + BeebAsm is free software: you can redistribute it and/or modify it under the terms of the GNU 13.14 + General Public License as published by the Free Software Foundation, either version 3 of the 13.15 + License, or (at your option) any later version. 13.16 + 13.17 + BeebAsm is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 13.18 + even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13.19 + GNU General Public License for more details. 13.20 + 13.21 + You should have received a copy of the GNU General Public License along with BeebAsm, as 13.22 + COPYING.txt. If not, see <http://www.gnu.org/licenses/>. 13.23 +*/ 13.24 +/*************************************************************************************************/ 13.25 + 13.26 +#include <cmath> 13.27 +#include <iostream> 13.28 + 13.29 +#include "macro.h" 13.30 + 13.31 + 13.32 +using namespace std; 13.33 + 13.34 + 13.35 +MacroTable* MacroTable::m_gInstance = NULL; 13.36 + 13.37 + 13.38 +/*************************************************************************************************/ 13.39 +/** 13.40 + MacroTable::Create() 13.41 + 13.42 + Creates the MacroTable singleton 13.43 +*/ 13.44 +/*************************************************************************************************/ 13.45 +void MacroTable::Create() 13.46 +{ 13.47 + assert( m_gInstance == NULL ); 13.48 + 13.49 + m_gInstance = new MacroTable; 13.50 +} 13.51 + 13.52 + 13.53 + 13.54 +/*************************************************************************************************/ 13.55 +/** 13.56 + MacroTable::Destroy() 13.57 + 13.58 + Destroys the MacroTable singleton 13.59 +*/ 13.60 +/*************************************************************************************************/ 13.61 +void MacroTable::Destroy() 13.62 +{ 13.63 + assert( m_gInstance != NULL ); 13.64 + 13.65 + delete m_gInstance; 13.66 + m_gInstance = NULL; 13.67 +} 13.68 + 13.69 + 13.70 + 13.71 +/*************************************************************************************************/ 13.72 +/** 13.73 + MacroTable::MacroTable() 13.74 + 13.75 + MacroTable constructor 13.76 +*/ 13.77 +/*************************************************************************************************/ 13.78 +MacroTable::MacroTable() 13.79 +{ 13.80 +} 13.81 + 13.82 + 13.83 + 13.84 +/*************************************************************************************************/ 13.85 +/** 13.86 + MacroTable::~MacroTable() 13.87 + 13.88 + MacroTable destructor 13.89 +*/ 13.90 +/*************************************************************************************************/ 13.91 +MacroTable::~MacroTable() 13.92 +{ 13.93 + for ( map< std::string, Macro* >::iterator it = m_map.begin(); it != m_map.end(); ++it ) 13.94 + { 13.95 + delete it->second; 13.96 + } 13.97 +} 13.98 + 13.99 + 13.100 +/*************************************************************************************************/ 13.101 +/** 13.102 + MacroTable::Add() 13.103 + 13.104 + Adds a new macro to the table 13.105 +*/ 13.106 +/*************************************************************************************************/ 13.107 +void MacroTable::Add( Macro* macro ) 13.108 +{ 13.109 + if ( macro != NULL ) 13.110 + { 13.111 + m_map.insert( make_pair( macro->GetName(), macro ) ); 13.112 + } 13.113 +} 13.114 + 13.115 + 13.116 +/*************************************************************************************************/ 13.117 +/** 13.118 + MacroTable::Exists() 13.119 + 13.120 + Returns whether or not the named macro yet exists 13.121 +*/ 13.122 +/*************************************************************************************************/ 13.123 +bool MacroTable::Exists( const string& name ) const 13.124 +{ 13.125 + return ( m_map.count( name ) > 0 ); 13.126 +} 13.127 + 13.128 + 13.129 +/*************************************************************************************************/ 13.130 +/** 13.131 + MacroTable::Get() 13.132 + 13.133 + Returns a reference to the named macro 13.134 +*/ 13.135 +/*************************************************************************************************/ 13.136 +const Macro* MacroTable::Get( const string& name ) const 13.137 +{ 13.138 + if ( Exists( name ) ) 13.139 + { 13.140 + return m_map.find( name )->second; 13.141 + } 13.142 + else 13.143 + { 13.144 + return NULL; 13.145 + } 13.146 +}
14.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 14.2 +++ b/src/macro.h Sun Mar 06 18:19:27 2011 +0100 14.3 @@ -0,0 +1,101 @@ 14.4 +/*************************************************************************************************/ 14.5 +/** 14.6 + macro.h 14.7 + 14.8 + 14.9 + Copyright (C) Rich Talbot-Watkins 2007 - 2011 14.10 + 14.11 + This file is part of BeebAsm. 14.12 + 14.13 + BeebAsm is free software: you can redistribute it and/or modify it under the terms of the GNU 14.14 + General Public License as published by the Free Software Foundation, either version 3 of the 14.15 + License, or (at your option) any later version. 14.16 + 14.17 + BeebAsm is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 14.18 + even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14.19 + GNU General Public License for more details. 14.20 + 14.21 + You should have received a copy of the GNU General Public License along with BeebAsm, as 14.22 + COPYING.txt. If not, see <http://www.gnu.org/licenses/>. 14.23 +*/ 14.24 +/*************************************************************************************************/ 14.25 + 14.26 +#ifndef MACRO_H_ 14.27 +#define MACRO_H_ 14.28 + 14.29 +#include <cassert> 14.30 +#include <cstdlib> 14.31 +#include <map> 14.32 +#include <string> 14.33 +#include <vector> 14.34 + 14.35 + 14.36 +class Macro 14.37 +{ 14.38 +public: 14.39 + 14.40 + void SetName( const std::string& name ) 14.41 + { 14.42 + m_name = name; 14.43 + } 14.44 + 14.45 + void AddParameter( const std::string& param ) 14.46 + { 14.47 + m_parameters.push_back( param ); 14.48 + } 14.49 + 14.50 + void AddLine( const std::string& line ) 14.51 + { 14.52 + m_content.push_back( line ); 14.53 + } 14.54 + 14.55 + const std::string& GetName() const 14.56 + { 14.57 + return m_name; 14.58 + } 14.59 + 14.60 + int GetNumberOfParameters() const 14.61 + { 14.62 + return m_parameters.size(); 14.63 + } 14.64 + 14.65 + const std::string& GetParameter( int i ) const 14.66 + { 14.67 + return m_parameters[ i ]; 14.68 + } 14.69 + 14.70 + 14.71 +private: 14.72 + 14.73 + std::string m_name; 14.74 + std::vector< std::string > m_parameters; 14.75 + std::vector< std::string > m_content; 14.76 +}; 14.77 + 14.78 + 14.79 + 14.80 +class MacroTable 14.81 +{ 14.82 +public: 14.83 + 14.84 + static void Create(); 14.85 + static void Destroy(); 14.86 + static inline MacroTable& Instance() { assert( m_gInstance != NULL ); return *m_gInstance; } 14.87 + 14.88 + void Add( Macro* macro ); 14.89 + bool Exists( const std::string& name ) const; 14.90 + const Macro* Get( const std::string& name ) const; 14.91 + 14.92 +private: 14.93 + 14.94 + MacroTable(); 14.95 + ~MacroTable(); 14.96 + 14.97 + std::map< std::string, Macro* > m_map; 14.98 + 14.99 + static MacroTable* m_gInstance; 14.100 +}; 14.101 + 14.102 + 14.103 + 14.104 +#endif // MACRO_H_
15.1 --- a/src/main.cpp Fri Mar 04 02:01:51 2011 +0000 15.2 +++ b/src/main.cpp Sun Mar 06 18:19:27 2011 +0100 15.3 @@ -35,6 +35,7 @@ 15.4 #include "symboltable.h" 15.5 #include "discimage.h" 15.6 #include "BASIC.h" 15.7 +#include "macro.h" 15.8 15.9 15.10 using namespace std; 15.11 @@ -201,6 +202,7 @@ 15.12 15.13 SymbolTable::Create(); 15.14 ObjectCode::Create(); 15.15 + MacroTable::Create(); 15.16 SetupBASICTables(); 15.17 15.18 time_t randomSeed = time( NULL ); 15.19 @@ -244,6 +246,7 @@ 15.20 cerr << "warning: no SAVE command in source file." << endl; 15.21 } 15.22 15.23 + MacroTable::Destroy(); 15.24 ObjectCode::Destroy(); 15.25 SymbolTable::Destroy(); 15.26 GlobalData::Destroy();
16.1 --- a/src/sourcefile.cpp Fri Mar 04 02:01:51 2011 +0000 16.2 +++ b/src/sourcefile.cpp Sun Mar 06 18:19:27 2011 +0100 16.3 @@ -50,7 +50,8 @@ 16.4 */ 16.5 /*************************************************************************************************/ 16.6 SourceFile::SourceFile( const char* pFilename ) 16.7 - : m_pFilename( pFilename ), 16.8 + : m_currentMacro( NULL ), 16.9 + m_pFilename( pFilename ), 16.10 m_lineNumber( 1 ), 16.11 m_filePointer( 0 ) 16.12 { 16.13 @@ -190,12 +191,12 @@ 16.14 SourceFile::AddFor() 16.15 */ 16.16 /*************************************************************************************************/ 16.17 -void SourceFile::AddFor( string varName, 16.18 +void SourceFile::AddFor( const string& varName, 16.19 double start, 16.20 double end, 16.21 double step, 16.22 int filePtr, 16.23 - string line, 16.24 + const string& line, 16.25 int column ) 16.26 { 16.27 if ( m_forStackPtr == MAX_FOR_LEVELS ) 16.28 @@ -232,7 +233,7 @@ 16.29 Braces for scoping variables are just FORs in disguise... 16.30 */ 16.31 /*************************************************************************************************/ 16.32 -void SourceFile::OpenBrace( string line, int column ) 16.33 +void SourceFile::OpenBrace( const string& line, int column ) 16.34 { 16.35 if ( m_forStackPtr == MAX_FOR_LEVELS ) 16.36 { 16.37 @@ -262,7 +263,7 @@ 16.38 SourceFile::UpdateFor() 16.39 */ 16.40 /*************************************************************************************************/ 16.41 -void SourceFile::UpdateFor( string line, int column ) 16.42 +void SourceFile::UpdateFor( const string& line, int column ) 16.43 { 16.44 if ( m_forStackPtr == 0 ) 16.45 { 16.46 @@ -306,7 +307,7 @@ 16.47 Braces for scoping variables are just FORs in disguise... 16.48 */ 16.49 /*************************************************************************************************/ 16.50 -void SourceFile::CloseBrace( string line, int column ) 16.51 +void SourceFile::CloseBrace( const string& line, int column ) 16.52 { 16.53 if ( m_forStackPtr == 0 ) 16.54 { 16.55 @@ -379,7 +380,7 @@ 16.56 SourceFile::AddIfLevel() 16.57 */ 16.58 /*************************************************************************************************/ 16.59 -void SourceFile::AddIfLevel( string line, int column ) 16.60 +void SourceFile::AddIfLevel( const string& line, int column ) 16.61 { 16.62 if ( m_ifStackPtr == MAX_IF_LEVELS ) 16.63 { 16.64 @@ -419,7 +420,7 @@ 16.65 SourceFile::StartElse() 16.66 */ 16.67 /*************************************************************************************************/ 16.68 -void SourceFile::StartElse( string line, int column ) 16.69 +void SourceFile::StartElse( const string& line, int column ) 16.70 { 16.71 if ( m_ifStack[ m_ifStackPtr - 1 ].m_hadElse ) 16.72 { 16.73 @@ -438,7 +439,7 @@ 16.74 SourceFile::StartElif() 16.75 */ 16.76 /*************************************************************************************************/ 16.77 -void SourceFile::StartElif( string line, int column ) 16.78 +void SourceFile::StartElif( const string& line, int column ) 16.79 { 16.80 if ( m_ifStack[ m_ifStackPtr - 1 ].m_hadElse ) 16.81 { 16.82 @@ -455,7 +456,7 @@ 16.83 SourceFile::RemoveIfLevel() 16.84 */ 16.85 /*************************************************************************************************/ 16.86 -void SourceFile::RemoveIfLevel( string line, int column ) 16.87 +void SourceFile::RemoveIfLevel( const string& line, int column ) 16.88 { 16.89 if ( m_ifStackPtr == 0 ) 16.90 { 16.91 @@ -464,3 +465,51 @@ 16.92 16.93 m_ifStackPtr--; 16.94 } 16.95 + 16.96 + 16.97 + 16.98 +/*************************************************************************************************/ 16.99 +/** 16.100 + SourceFile::StartMacro() 16.101 +*/ 16.102 +/*************************************************************************************************/ 16.103 +void SourceFile::StartMacro( const string& line, int column ) 16.104 +{ 16.105 + if ( GlobalData::Instance().IsFirstPass() ) 16.106 + { 16.107 + if ( m_currentMacro == NULL ) 16.108 + { 16.109 + m_currentMacro = new Macro(); 16.110 + } 16.111 + else 16.112 + { 16.113 + throw AsmException_SyntaxError_NoNestedMacros( line, column ); 16.114 + } 16.115 + } 16.116 + 16.117 + AddIfLevel( line, column ); 16.118 +} 16.119 + 16.120 + 16.121 + 16.122 +/*************************************************************************************************/ 16.123 +/** 16.124 + SourceFile::EndMacro() 16.125 +*/ 16.126 +/*************************************************************************************************/ 16.127 +void SourceFile::EndMacro( const string& line, int column ) 16.128 +{ 16.129 + if ( GlobalData::Instance().IsFirstPass() && 16.130 + m_currentMacro == NULL ) 16.131 + { 16.132 + throw AsmException_SyntaxError_EndMacroUnexpected( line, column - 8 ); 16.133 + } 16.134 + 16.135 + RemoveIfLevel( line, column ); 16.136 + 16.137 + if ( GlobalData::Instance().IsFirstPass() ) 16.138 + { 16.139 + MacroTable::Instance().Add( m_currentMacro ); 16.140 + m_currentMacro = NULL; 16.141 + } 16.142 +}
17.1 --- a/src/sourcefile.h Fri Mar 04 02:01:51 2011 +0000 17.2 +++ b/src/sourcefile.h Sun Mar 06 18:19:27 2011 +0100 17.3 @@ -26,6 +26,7 @@ 17.4 #include <fstream> 17.5 #include <string> 17.6 #include <vector> 17.7 +#include "macro.h" 17.8 17.9 17.10 class SourceFile 17.11 @@ -85,32 +86,38 @@ 17.12 int m_ifStackPtr; 17.13 If m_ifStack[ MAX_IF_LEVELS ]; 17.14 17.15 + Macro* m_currentMacro; 17.16 + 17.17 + 17.18 public: 17.19 17.20 - void OpenBrace( std::string line, int column ); 17.21 - void CloseBrace( std::string line, int column ); 17.22 + void OpenBrace( const std::string& line, int column ); 17.23 + void CloseBrace( const std::string& line, int column ); 17.24 17.25 - void AddFor( std::string varName, 17.26 + void AddFor( const std::string& varName, 17.27 double start, 17.28 double end, 17.29 double step, 17.30 int filePtr, 17.31 - std::string line, 17.32 + const std::string& line, 17.33 int column ); 17.34 17.35 - void UpdateFor( std::string line, int column ); 17.36 + void UpdateFor( const std::string& line, int column ); 17.37 17.38 inline int GetForLevel() const { return m_forStackPtr; } 17.39 + inline Macro* GetCurrentMacro() { return m_currentMacro; } 17.40 17.41 std::string GetSymbolNameSuffix( int level = -1 ) const; 17.42 17.43 bool IsIfConditionTrue() const; 17.44 - void AddIfLevel( std::string line, int column ); 17.45 + void AddIfLevel( const std::string& line, int column ); 17.46 void SetCurrentIfCondition( bool b ); 17.47 - void StartElse( std::string line, int column ); 17.48 - void StartElif( std::string line, int column ); 17.49 - void ToggleCurrentIfCondition( std::string line, int column ); 17.50 - void RemoveIfLevel( std::string line, int column ); 17.51 + void StartElse( const std::string& line, int column ); 17.52 + void StartElif( const std::string& line, int column ); 17.53 + void ToggleCurrentIfCondition( const std::string& line, int column ); 17.54 + void RemoveIfLevel( const std::string& line, int column ); 17.55 + void StartMacro( const std::string& line, int column ); 17.56 + void EndMacro( const std::string& line, int column ); 17.57 17.58 17.59 private:
18.1 --- a/src/tokens.h Fri Mar 04 02:01:51 2011 +0000 18.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 18.3 @@ -1,36 +0,0 @@ 18.4 -/*************************************************************************************************/ 18.5 -/** 18.6 - tokens.h 18.7 - 18.8 - All the data used by the assembler 18.9 -*/ 18.10 -/*************************************************************************************************/ 18.11 - 18.12 -// Token table 18.13 - 18.14 -LineParser::Token LineParser::m_gaTokenTable[] = 18.15 -{ 18.16 - { ".", &LineParser::HandleDefineLabel }, 18.17 - { "\\", &LineParser::HandleDefineComment }, 18.18 - { ";", &LineParser::HandleDefineComment }, 18.19 - { ":", &LineParser::HandleStatementSeparator }, 18.20 - { "PRINT", &LineParser::HandlePrint }, 18.21 - { "ORG", &LineParser::HandleOrg }, 18.22 - { "INCLUDE", &LineParser::HandleInclude }, 18.23 - { "EQUB", &LineParser::HandleEqub }, 18.24 - { "EQUS", &LineParser::HandleEqub }, 18.25 - { "EQUW", &LineParser::HandleEquw }, 18.26 - { "SAVE", &LineParser::HandleSave }, 18.27 - { "FOR", &LineParser::HandleFor }, 18.28 - { "NEXT", &LineParser::HandleNext }, 18.29 - { "IF", &LineParser::HandleIf }, 18.30 - { "ELSE", &LineParser::HandleElse }, 18.31 - { "ENDIF", &LineParser::HandleEndif }, 18.32 - { "ALIGN", &LineParser::HandleAlign }, 18.33 - { "SKIP", &LineParser::HandleSkip } 18.34 -}; 18.35 - 18.36 - 18.37 - 18.38 - 18.39 -
