From c6fea99bff4f8cabdb3ad1f5a1e39f7e662b32b9 Mon Sep 17 00:00:00 2001 From: jonnosan Date: Sun, 21 Mar 2010 11:26:55 +0000 Subject: [PATCH] first (incomplete) version of webnoter git-svn-id: http://svn.code.sf.net/p/netboot65/code@251 93682198-c243-4bdb-bd91-e943c89aac3b --- client/cfg/c64prg.cfg | 2 + client/examples/Makefile | 15 +- client/examples/form.html | 12 + client/examples/webnoter.s | 841 +++++++++++++++++++++++++++++++++++++ 4 files changed, 867 insertions(+), 3 deletions(-) create mode 100644 client/examples/form.html create mode 100644 client/examples/webnoter.s diff --git a/client/cfg/c64prg.cfg b/client/cfg/c64prg.cfg index 7f2ac9c..33e8af7 100644 --- a/client/cfg/c64prg.cfg +++ b/client/cfg/c64prg.cfg @@ -3,6 +3,7 @@ MEMORY { IP65ZP: start = $5f, size = $10, type = rw; RAM: start = $07FF, size = $77ab, file = %O; RAM3000: start = $3000, size = $4800, type=rw; + RAM4000: start = $4000, size = $3800, type=rw; DISCARD: start = $77FF, size = $10; } SEGMENTS { @@ -15,6 +16,7 @@ SEGMENTS { IP65_DEFAULTS: load = RAM, type = rw,define = yes, optional=yes; BSS: load = RAM, type = bss, optional=yes; SAFE_BSS: load = RAM3000, type = bss, optional=yes; + BSS4K: load = RAM4000, type = bss, optional=yes; APP_SCRATCH: load = RAM, type = bss, optional=yes; ZEROPAGE: load = ZP, type = zp, optional=yes; IP65ZP: load = IP65ZP, type = zp, optional=yes; diff --git a/client/examples/Makefile b/client/examples/Makefile index d6d7f5c..575c9f3 100644 --- a/client/examples/Makefile +++ b/client/examples/Makefile @@ -14,7 +14,7 @@ INCFILES=\ ../inc/commonprint.i\ ../inc/net.i\ -all: upnatom.prg upnatom.d64 +all: upnatom.prg upnatom.d64 webnoter.d64 %.o: %.s $(AS) $(AFLAGS) $< @@ -24,7 +24,13 @@ upnatom.o: upnatom.s sine_data.i sine_data.i: make_sine_data.rb ruby make_sine_data.rb - + +webnoter.o: webnoter.s form.html + $(AS) $(AFLAGS) $< + +webnoter.prg: webnoter.o $(IP65TCPLIB) $(C64PROGLIB) $(INCFILES) ../cfg/c64prg.cfg + $(LD) -m webnoter.map -vm -C ../cfg/c64prg.cfg -o webnoter.prg $(AFLAGS) $< $(IP65TCPLIB) $(C64PROGLIB) $(NT2PLAY) + upnatom.prg: upnatom.o nt2play.o $(IP65TCPLIB) $(C64PROGLIB) $(INCFILES) ../cfg/c64prg.cfg $(LD) -m upnatom.map -vm -C ../cfg/c64prg.cfg -o upnatom.prg $(AFLAGS) $< $(IP65TCPLIB) $(C64PROGLIB) $(NT2PLAY) # cp upnatom.prg ../../server/boot/ @@ -32,12 +38,15 @@ upnatom.prg: upnatom.o nt2play.o $(IP65TCPLIB) $(C64PROGLIB) $(INCFILES) ../cfg/ %.prg: %.o $(IP65TCPLIB) $(C64PROGLIB) $(INCFILES) ../cfg/c64prg.cfg $(LD) -m $*.map -vm -C ../cfg/c64prg.cfg -o $*.prg $(AFLAGS) $< $(IP65TCPLIB) $(C64PROGLIB) - upnatom.d64: upnatom.prg url.cfg cp upnatom.prg autoexec.prg ripxplore.rb --init CbmDos upnatom.d64 -a autoexec.prg ripxplore.rb upnatom.d64 -a url.cfg -t C64Seq +webnoter.d64: webnoter.prg + cp webnoter.prg autoexec.prg + ripxplore.rb --init CbmDos webnoter.d64 -a autoexec.prg + httpd.prg: httpd.asm $(DA) httpd.asm -ohttpd.prg diff --git a/client/examples/form.html b/client/examples/form.html new file mode 100644 index 0000000..b791a95 --- /dev/null +++ b/client/examples/form.html @@ -0,0 +1,12 @@ + + +
+ + + + +
WebNoter
%?mhey %$h, thanks for saying '%$m'!%.
Your Handle:
Your Message:
\ No newline at end of file diff --git a/client/examples/webnoter.s b/client/examples/webnoter.s new file mode 100644 index 0000000..d3cd252 --- /dev/null +++ b/client/examples/webnoter.s @@ -0,0 +1,841 @@ + +.include "../inc/common.i" + +.ifndef KPR_API_VERSION_NUMBER + .define EQU = + .include "../inc/kipper_constants.i" +.endif + +print_a = $ffd2 + + +SCREEN_RAM = $0400 +COLOUR_RAM = $d800 +VIC_CTRL_A = $d011 +VIC_RASTER_REG = $d012 +VIC_CTRL_B = $d016 +VIC_MEMORY_CTRL=$d018 +VIC_IRQ_FLAG = $d019 + +copy_src = $24 + + +IRQ_VECTOR=$fffe + +MUSIC_BASE=$1000 ;where we relocate our music routine to +PLAYER_INIT=0 +PLAYER_PLAY=3 + +BORDER_COLOR = $d020 +BACKGROUND_COLOR_0 = $d021 +SCROLL_DELAY=4 +CHARS_PER_LINE = 40 +SCROLL_LINE=12 +SCROLL_RAM = SCREEN_RAM+(SCROLL_LINE*CHARS_PER_LINE) + +TOP_BORDER_SCAN_LINES = 50 + + +BLACK = 0 +WHITE = 1 +RED = 2 +CYAN = 3 +PURPLE = 4 +GREEN = 5 +BLUE = 6 +YELLOW = 7 +ORANGE = 8 +BROWN = 9 +LIGHT_RED = 10 +DARK_GRAY = 11 +GRAY = 12 +LIGHT_GREEN = 13 +LIGHT_BLUE = 14 +LIGHT_GRAY = 15 + +.macro start_irq + pha + txa + pha + tya + pha + +.endmacro + + +.macro end_irq + pla + tay + pla + tax + pla +.endmacro + +.macro wait_next_raster + lda VIC_RASTER_REG +@loop: + cmp VIC_RASTER_REG + beq @loop +.endmacro + +.macro kippercall function_number + ldy function_number + jsr KPR_DISPATCH_VECTOR +.endmacro + +.zeropage +temp_buff: .res 2 +pptr: .res 2 + +.segment "STARTUP" ;this is what gets put at the start of the file on the C64 + +.word basicstub ; load address + +basicstub: + .word @nextline + .word 2003 + .byte $9e + .byte <(((init / 1000) .mod 10) + $30) + .byte <(((init / 100 ) .mod 10) + $30) + .byte <(((init / 10 ) .mod 10) + $30) + .byte <(((init ) .mod 10) + $30) + .byte 0 +@nextline: + .word 0 + +init: + + ldax #KPR_CART_SIGNATURE ;where signature should be in cartridge (if cart is banked in) +look_for_signature: + stax temp_buff + ldy #5 +@check_one_byte: + lda (temp_buff),y + cmp kipper_signature,y + bne @bad_match + dey + bpl @check_one_byte + jmp @found_kipper_signature + +@bad_match: + ldax #kipper_api_not_found_message + jsr print +@loop: + jmp @loop + rts +@found_kipper_signature: + + ldax #init_msg + jsr print + kippercall #KPR_INITIALIZE + bcc @init_ok + jsr print_cr + ldax #failed_msg + jsr print + jsr print_cr + jsr print_errorcode + jmp reset_after_keypress +@init_ok: + +;if we got here, we have found the KIPPER API and initialised the IP stack + + jsr setup_static_scroll_text + + lda #0 + jsr clear_screen + lda #DARK_GRAY + sta BORDER_COLOR + lda #YELLOW + sta BACKGROUND_COLOR_0 + + + + ;copy our music data up to a temp buffer (in case it gets overwritten by + ;one of the other unpacking moves) + ldax #musicdata+2 ;skip over the 2 byte address + stax param_buffer+KPR_BLOCK_SRC + ldax #download_buffer + stax param_buffer+KPR_BLOCK_DEST + ldax #musicdata_size-2 ;don't copy the 2 byte address + stax param_buffer+KPR_BLOCK_SIZE + ldax #param_buffer + kippercall #KPR_BLOCK_COPY + + ;copy our font data and the sprite data to $3000..$3fff + ldax #charset_font + stax param_buffer+KPR_BLOCK_SRC + ldax #$3000 + stax param_buffer+KPR_BLOCK_DEST + ldax #MUSIC_BASE + stax param_buffer+KPR_BLOCK_SIZE + ldax #param_buffer + kippercall #KPR_BLOCK_COPY + + ;should now be now safe to copy the music data back down + ;copy our music data to $1000..$1fff + ldax #download_buffer + stax param_buffer+KPR_BLOCK_SRC + ldax #MUSIC_BASE + stax param_buffer+KPR_BLOCK_DEST + ldax #musicdata_size-2 ;don't copy the 2 byte address + stax param_buffer+KPR_BLOCK_SIZE + ldax #param_buffer + kippercall #KPR_BLOCK_COPY + + lda #$1c ; use charset at $3000 + sta VIC_MEMORY_CTRL + + + sei ;disable maskable IRQs + + lda #$7f + sta $dc0d ;disable timer interrupts which can be generated by the two CIA chips + sta $dd0d ;the kernal uses such an interrupt to flash the cursor and scan the keyboard, so we better + ;stop it. + + lda $dc0d ;by reading this two registers we negate any pending CIA irqs. + lda $dd0d ;if we don't do this, a pending CIA irq might occur after we finish setting up our irq. + ;we don't want that to happen. + + lda #$01 ;this is how to tell the VICII to generate a raster interrupt + sta $d01a + + lda #$00 ;this is how to tell at which rasterline we want the irq to be triggered + sta VIC_RASTER_REG + + + ;copy KERNAL to the RAM underneath, in case any ip65 routines need it + ldax #$e000 + stax param_buffer+KPR_BLOCK_SRC + stax param_buffer+KPR_BLOCK_DEST + ldax #$1FFF + stax param_buffer+KPR_BLOCK_SIZE + ldax #param_buffer + kippercall #KPR_BLOCK_COPY + + ;copy KIPPER cart to the RAM underneath, so we can swap it out and modify the IRQ vector + ldax #$8000 + stax param_buffer+KPR_BLOCK_SRC + stax param_buffer+KPR_BLOCK_DEST + ldax #$4000 + stax param_buffer+KPR_BLOCK_SIZE + ldax #param_buffer + kippercall #KPR_BLOCK_COPY + + + lda #$35 ;we turn off the BASIC and KERNAL rom here, so we can overwrite the IRQ vector at $fffe + sta $01 ;the cpu now sees RAM everywhere except at $d000-$e000, where still the registers of + ;SID/VICII/etc are visible + + jsr setup_sprites + + jsr setup_music + + + jsr set_next_irq_jump + cli ;enable maskable interrupts again + + +;position for the first text + + jsr reset_input_buffer + + lda #0 + sta scroll_buffer_1 ;set this buffer to be an empty string, in case we try to scroll it + + +start_web_server: + ldax #httpd_callback + kippercall #KPR_HTTPD_START ;this will only return if there is an error + rts + + +reset_input_buffer: + ldax #scroll_buffer_0 + stax current_input_ptr + rts + +httpd_callback: + lda #'h' + kippercall #KPR_HTTPD_GET_VAR_VALUE + bcs @no_handle + stax copy_src + ldy #0 + +@copy_handle_loop: + lda (copy_src),y + beq @end_of_handle + sta message_buffer,y + iny + bne @copy_handle_loop +@end_of_handle: + tya + pha + lda #'m' + kippercall #KPR_HTTPD_GET_VAR_VALUE + stax copy_src + pla + tax + bcs @end_of_message + + lda #':' + sta message_buffer,x + inx + lda #' ' + sta message_buffer,x + inx + ldy #0 +@copy_message_loop: + lda (copy_src),y + beq @end_of_message + sta message_buffer,x + iny + inx + bne @copy_message_loop +@end_of_message: + lda #0 + sta message_buffer,x + + +@no_handle: + + ldax #html + ldy #2 ;text/html + clc + rts + + +;set up the tune +setup_music: + lda #$00 ;init subtune 0 + jsr MUSIC_BASE+PLAYER_INIT + rts + +setup_sprites: + + ;turn on all 8 sprites + lda #$FF + sta $d015 + + ldx #$07 +@setup_sprite: + ;position each sprite + txa + asl + tay + lda sprite_x_pos,x + sta $d000,y ;sprite 0 X pos (LSB) + lda #0 + sta $d001,y ;sprite 0 Y pos + + ;colour sprite 0 + lda #BLUE + sta $d027,x ;sprite 0 color + + ;select bitmap for sprite + sec + lda sprite_text,x + sbc #'A' + clc + adc #<($3800/64) ;sprite font should be relocated to $3000 + sta SCREEN_RAM+$03f8,x + dex + bpl @setup_sprite + + lda sprite_x_msb + sta $d010 + + ;turn on multicolor mode for all 8 sprites + lda #$FF + sta $d01c + + sta sprite_ticker + + lda #DARK_GRAY + sta $d025 ;sprite multicolor register 0 + lda #LIGHT_GRAY + sta $d026 ;sprite multicolor register 1 + + rts + + +clear_screen: + + ldx #$00 + lda #$20 + +: + sta SCREEN_RAM,x + sta SCREEN_RAM+$100,x + sta SCREEN_RAM+$200,x + sta SCREEN_RAM+$300,x + sta COLOUR_RAM,x + sta COLOUR_RAM+$100,x + sta COLOUR_RAM+$200,x + sta COLOUR_RAM+$300,x + + dex + bne :- + rts + +set_next_irq_jump: + inc jump_counter + + lda jump_counter + asl + asl +load_next_raster_entry: + tax + lda raster_jump_table,x ;bit 9 of raster to trigger on + + cmp #$ff + bne not_last_entry + lda #0 + sta jump_counter + jmp load_next_raster_entry +not_last_entry: + ora #$18 ;turn on bits 3 & 4 + sta VIC_CTRL_A + lda raster_jump_table+1,x ;bits 0..7 of raster to trigger on + sta VIC_RASTER_REG + lda raster_jump_table+2,x ;LSB of IRQ handler + sta IRQ_VECTOR + lda raster_jump_table+3,x ;LSB of IRQ handler + sta IRQ_VECTOR+1 + rts + +exit_from_irq: + jsr set_next_irq_jump + lda #$ff ;this is the orthodox and safe way of clearing the interrupt condition of the VICII. + sta VIC_IRQ_FLAG;if you don't do this the interrupt condition will be present all the time and you end + ;up having the CPU running the interrupt code all the time, as when it exists the + ;interrupt, the interrupt request from the VICII will be there again regardless of the + ;rasterline counter. + + end_irq + rti + + + +scroll_text_irq: + start_irq + lda scroll_timer + bne done_scrolling_message + lda #SCROLL_DELAY + sta scroll_timer + ldx #1 + ldy #0 +scroll_1_char: + lda SCROLL_RAM,x + sta SCROLL_RAM,y + lda SCROLL_RAM+40,x + sta SCROLL_RAM+40,y + + inx + iny + cpx #CHARS_PER_LINE + bne scroll_1_char + + + jsr get_a + cmp #0 + beq last_char_in_message + sta SCROLL_RAM+CHARS_PER_LINE-1 + clc + adc #$80 + sta SCROLL_RAM+CHARS_PER_LINE+40-1 + + jmp done_scrolling_message + + +last_char_in_message: + jsr reset_input_buffer + +done_scrolling_message: + dec scroll_timer + + jmp exit_from_irq + + +scroll_timer: .byte 1 +scroll_counter: .byte 0 + + +pixel_scroll_irq: + start_irq + wait_next_raster +; set X scroll offset + lda scroll_timer + clc + asl + clc + and #$07 + sta VIC_CTRL_B + + jmp exit_from_irq + +move_sprites_irq: + start_irq + wait_next_raster + ldy sprite_ticker + inc sprite_ticker + + ldx #$0e ;7*2 +@position_sprite: + lda sprite_y_pos,y + sta $d001,x ;sprite 0 Y pos + + ;change colour when the sprite goes off screen +; cmp #$ff ;are we off the screen? +; bne @not_off_screen +; txa +; pha +; lsr +; tax +; inc $d027,x ;sprite color +; pla +; tax +;@not_off_screen: + + txa + beq @y_set + dex + dex +@mod_y: + iny + iny + iny + dex + dex + bpl @mod_y +@y_set: + + tax + dex + dex + bpl @position_sprite + + jmp exit_from_irq + + +setup_static_scroll_text: + ldax #scroll_buffer_0 + stax current_output_ptr + ldax #scroll_template + stax current_input_ptr +@next_byte: + jsr get_a + beq @next_byte + cmp #'%' + beq @operator + pha + jsr emit_a + pla + bne @next_byte + rts + +@operator: + jsr get_a + cmp #'i' + bne @not_ip + lda #KPR_CFG_IP + jmp @loaded_offset +@not_ip: + cmp #'g' + bne @not_gateway + lda #KPR_CFG_GATEWAY + jmp @loaded_offset +@not_gateway: + cmp #'d' + bne @not_dns + lda #KPR_CFG_DNS_SERVER + jmp @loaded_offset +@not_dns: + jmp @next_byte + +@loaded_offset: + sta param_offset + kippercall #KPR_GET_IP_CONFIG + adc param_offset + bcc :+ + inx +: + jsr emit_dotted_quad + + + jmp @next_byte + +;emit the 4 bytes pointed at by AX as dotted decimals +emit_dotted_quad: + sta pptr + stx pptr + 1 + ldy #0 + lda (pptr),y + jsr emit_decimal + lda #'.' + jsr emit_a + + ldy #1 + lda (pptr),y + jsr emit_decimal + lda #'.' + jsr emit_a + + ldy #2 + lda (pptr),y + jsr emit_decimal + lda #'.' + jsr emit_a + + ldy #3 + lda (pptr),y + jsr emit_decimal + + rts + +emit_decimal: ;emit byte in A as a decimal number + pha + sta temp_bin ;save + sed ; Switch to decimal mode + lda #0 ; Ensure the result is clear + sta temp_bcd + sta temp_bcd+1 + ldx #8 ; The number of source bits + : + asl temp_bin+0 ; Shift out one bit + lda temp_bcd+0 ; And add into result + adc temp_bcd+0 + sta temp_bcd+0 + lda temp_bcd+1 ; propagating any carry + adc temp_bcd+1 + sta temp_bcd+1 + dex ; And repeat for next bit + bne :- + + cld ;back to binary + + pla ;get back the original passed in number + bmi @emit_hundreds ; if N is set, the number is >=128 so emit all 3 digits + cmp #10 + bmi @emit_units + cmp #100 + bmi @emit_tens +@emit_hundreds: + lda temp_bcd+1 ;get the most significant digit + and #$0f + clc + adc #'0' + jsr emit_a + +@emit_tens: + lda temp_bcd + lsr + lsr + lsr + lsr + clc + adc #'0' + jsr emit_a +@emit_units: + lda temp_bcd + and #$0f + clc + adc #'0' + jsr emit_a + + rts + +reset_after_keypress: + ldax #press_a_key_to_continue + jsr print +@wait_key: + jsr $f142 ;not officially documented - where F13E (GETIN) falls through to if device # is 0 (KEYBD) + beq @wait_key + jmp $fce2 ;do a cold start + +print_errorcode: + ldax #error_code + jsr print + kippercall #KPR_GET_LAST_ERROR + kippercall #KPR_PRINT_HEX + jmp print_cr + + + + + +play_music_irq: +; inc BORDER_COLOR + start_irq + jsr MUSIC_BASE+PLAYER_PLAY +; dec BORDER_COLOR + jmp exit_from_irq + + +print: + sta pptr + stx pptr + 1 + +@print_loop: + ldy #0 + lda (pptr),y + beq @done_print + jsr print_a + inc pptr + bne @print_loop + inc pptr+1 + bne @print_loop ;if we ever get to $ffff, we've probably gone far enough ;-) +@done_print: + rts + +print_cr: + lda #13 + jmp print_a + +.data + +sprite_ticker: .byte 0 + +emit_a: +current_output_ptr=emit_a+1 + sta $ffff + inc current_output_ptr + bne :+ + inc current_output_ptr+1 +: + rts + +get_a: +current_input_ptr=get_a+1 + lda $ffff + inc current_input_ptr + bne :+ + inc current_input_ptr+1 +: + rts + + +raster_jump_table: + ;format: + ;offset meaning + ; $00 BIT 9 OF RASTER TO TRIGGER ON ($00 if bit 8 =0 , $80 if bit 8 =1) + ; $01 BITS 0..7 OF RASTER TO TRIGGER ON + ; $02 LSB OF ROUTINE TO JUMP TO + ; $03 MSB OF ROUTINE TO JUMP TO + ;table needs to end with a single byte $ff + ;table needs to be sorted by scanlines + .byte $0,$01 + .word scroll_text_irq + .byte $0,$20 + .word pixel_scroll_irq + + + .byte $0,$80 + .word play_music_irq + + .byte $80,$05 + .word move_sprites_irq + + .byte $ff ;end of list + +jump_counter: .byte 0 + + + +.data + +sprite_x_pos: +.byte $34,$54,$78,$90,$Bb,$Db,$Fb,$1b + +sprite_x_msb: +.byte $80 + +sprite_y_pos: +.repeat 128 + .byte 0 +.endrep +.include "sine_data.i" + +;.include "sine_data.i" + + + +sprite_text: + +.byte "KIPPERS_" ;options are A-Z, "[\]^_" + +scroll_template: +.byte "http://%i/ - WebNoter [enterprise edition] - http://%i/ - powered by kippers -" +.byte " ",0 + + + +kipper_api_not_found_message: + .byte "ERROR - KIPPER API NOT FOUND.",13,0 + +failed_msg: + .byte "FAILED", 0 + +ok_msg: + .byte "OK", 0 + + +init_msg: + .byte " INITIALIZING ",0 + +press_a_key_to_continue: + .byte "PRESS A KEY TO CONTINUE",13,0 + +kipper_signature: +.byte $4B,$49,$50,$50,$45,$52 ; "KIPPER" + +error_code: + .asciiz "ERROR CODE: " + + +html: + .incbin "form.html" +.byte 0 + + + +charset_font: + .incbin "font16x8.bin" +sprite_font: + .incbin "spud_letters.spr" +musicdata: +.incbin "tune.bin" +;.incbin "powertrain.bin" +musicdata_size=*-musicdata + + + +.segment "BSS4K" +;we want our variables to start at $4000, out of the way of our music player and the font data + +message_buffer: +.repeat 256 +.byte $64 +.endrepeat + +param_offset: .res 1 + +temp_bin: .res 1 +temp_bcd: .res 2 + + +param_buffer: .res $20 + +download_buffer: +download_buffer_length=4000 + .res download_buffer_length + +.res 10 ;filler +scroll_buffer_0: + .res 1000 + +scroll_buffer_1: + .res 1000 + +string_offset: .res 1 +