]> git.the-white-hart.net Git - vhdl/commitdiff
Add multi-file assembly project
authorrs <>
Sat, 4 Oct 2025 06:19:51 +0000 (01:19 -0500)
committerrs <>
Sat, 4 Oct 2025 06:19:51 +0000 (01:19 -0500)
projects/cpu_0/asm/build.sh [new file with mode: 0755]
projects/cpu_0/asm/entry.asm [new file with mode: 0644]
projects/cpu_0/asm/host.asm [new file with mode: 0644]
projects/cpu_0/asm/ps2_keyboard.asm [new file with mode: 0644]
projects/cpu_0/asm/runtime.asm [new file with mode: 0644]
projects/cpu_0/asm/timers.asm [new file with mode: 0644]
projects/cpu_0/asm/uart_console.asm [new file with mode: 0644]
projects/cpu_0/asm/vga_console.asm [new file with mode: 0644]

diff --git a/projects/cpu_0/asm/build.sh b/projects/cpu_0/asm/build.sh
new file mode 100755 (executable)
index 0000000..88dacf9
--- /dev/null
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+set -ev
+
+# runtime.asm must come first to place the ISR entry at address zero
+./as.py -o writer.bin -m writer.map runtime.asm vga_console.asm host.asm ps2_keyboard.asm uart_console.asm timers.asm entry.asm
diff --git a/projects/cpu_0/asm/entry.asm b/projects/cpu_0/asm/entry.asm
new file mode 100644 (file)
index 0000000..73ce9b1
--- /dev/null
@@ -0,0 +1,20 @@
+start:
+    ( Send greetz to the l33tz )
+    #32 greetz_uart call uart_puts
+    #32 greetz_vga call vga_console_puts
+
+    #8 0xa5i8 call host_seg_upper_set
+    #8 0xc3i8 call host_seg_lower_set
+    #8 0x02i8 call host_seg_dp_set
+
+halt:
+    #8 0xc0i8 #32 host_swled !8 drop
+_halt:
+    jmp _halt
+
+
+greetz_uart:
+    "Hellorld," 0x20i8 "through" 0x20i8 "the" 0x20i8 "UART!" 0x0ai8 0x0di8 0x00i8
+
+greetz_vga:
+    "Hellorld," 0x20i8 "through" 0x20i8 "VGA!" 0x0ai8 0x0di8 0x00i8
diff --git a/projects/cpu_0/asm/host.asm b/projects/cpu_0/asm/host.asm
new file mode 100644 (file)
index 0000000..ec340ad
--- /dev/null
@@ -0,0 +1,105 @@
+( Initialize host controller with reasonable defaults )
+( -- )
+host_reset:
+    ( Clear LEDs )
+    #8 0x00i8 #32 host_swled !8 drop
+    #8 0xffi8 #32 host_sseg0 !8 drop
+    #8 0xffi8 #32 host_sseg1 !8 drop
+    #8 0xffi8 #32 host_sseg2 !8 drop
+    #8 0xffi8 #32 host_sseg3 !8 drop
+    ;
+
+
+( Host flag interrupt )
+( -- )
+host_int:
+    ( Just acknowledge the interrupt and move on )
+    #32 host_flags @8
+    #32 host_flags !8 drop
+    ;
+
+
+( Print a byte to the seven-segment display upper byte )
+( b -- )
+host_seg_upper_set:
+    dup #8 0x0fi8 &        ( Extract lower nibble )
+    #32 host_seg_lut + @8       ( Look up segment value )
+    #32 host_sseg2 @8      ( Read existing value )
+    #8 0x80i8 & |          ( Mask out only the decimal point and combine )
+    #32 host_sseg2 !8 drop ( Write back to segment register )
+
+    lsr lsr lsr lsr        ( Extract upper nibble )
+    #32 host_seg_lut + @8       ( Look up segment value )
+    #32 host_sseg3 @8      ( Read existing value )
+    #8 0x80i8 & |          ( Mask out only decimal point and combine )
+    #32 host_sseg3 !8 drop ( Write back to segment register )
+
+    ;
+
+
+( Print a byte to the seven-segment display lower byte )
+( b -- )
+host_seg_lower_set:
+    dup #8 0x0fi8 &        ( Extract lower nibble )
+    #32 host_seg_lut + @8       ( Look up segment value )
+    #32 host_sseg0 @8      ( Read existing value )
+    #8 0x80i8 & |          ( Mask out only the decimal point and combine )
+    #32 host_sseg0 !8 drop ( Write back to segment register )
+
+    lsr lsr lsr lsr        ( Extract upper nibble )
+    #32 host_seg_lut + @8       ( Look up segment value )
+    #32 host_sseg1 @8      ( Read existing value )
+    #8 0x80i8 & |          ( Mask out only decimal point and combine )
+    #32 host_sseg1 !8 drop ( Write back to segment register )
+
+    ;
+
+
+( Clear the seven-segment display upper byte )
+( -- )
+seg_upper_clr:
+    #32 host_sseg2 @8 #8 0x7fi8 |  ( Read original value and clear all segments except point )
+    #32 host_sseg2 !8 drop         ( Write back into segment register )
+    #32 host_sseg3 @8 #8 0x7fi8 |  ( Read original value and clear all segments except point )
+    #32 host_sseg3 !8 drop         ( Write back into segment register )
+    ;
+
+
+( Clear the seven-segment display lower byte )
+( -- )
+seg_upper_clr:
+    #32 host_sseg0 @8 #8 0x7fi8 |  ( Read original value and clear all segments except point )
+    #32 host_sseg0 !8 drop         ( Write back into segment register )
+    #32 host_sseg1 @8 #8 0x7fi8 |  ( Read original value and clear all segments except point )
+    #32 host_sseg1 !8 drop         ( Write back into segment register )
+    ;
+
+
+( Turn on a decimal point on the seven-segment display )
+( n -- )
+host_seg_dp_set:
+    dup #8 0x03i8 - jn _host_seg_dp_set_x
+    #32 host_sseg0 +
+    dup @8 #8 0x7fi8 &
+    swap !8
+_host_seg_dp_set_x:
+    drop ;
+
+
+( Turn off a decimal point on the seven-segment display )
+( n -- )
+host_seg_dp_clr:
+    dup #8 0x03i8 - jn _host_seg_dp_clr_x
+    #32 host_sseg0 +
+    dup @8 #8 0x80i8 |
+    swap !8
+_host_seg_dp_clr_x:
+    drop ;
+
+
+( Look up table for seven-segment values for hex characters )
+host_seg_lut:
+    0x40i8 0x79i8 0x24i8 0x30i8
+    0x19i8 0x12i8 0x02i8 0x78i8
+    0x00i8 0x10i8 0x08i8 0x03i8
+    0x46i8 0x21i8 0x06i8 0x0ei8
diff --git a/projects/cpu_0/asm/ps2_keyboard.asm b/projects/cpu_0/asm/ps2_keyboard.asm
new file mode 100644 (file)
index 0000000..3510b0f
--- /dev/null
@@ -0,0 +1,13 @@
+( Reset the PS2 controller with reasonable defaults )
+( -- )
+ps2_reset:
+    ( Enable PS2 block and Rx interrupt )
+    #8 0x41i8 #32 ps2_ctrl  !8 drop
+    #8 0x01i8 #32 ps2_imask !8 drop
+    ;
+
+
+( PS2 interface interrupt )
+( -- )
+ps2_int:
+    ;
diff --git a/projects/cpu_0/asm/runtime.asm b/projects/cpu_0/asm/runtime.asm
new file mode 100644 (file)
index 0000000..1798a0c
--- /dev/null
@@ -0,0 +1,189 @@
+( ---------------------------------------------------------------------------- )
+( Global address definitions )
+
+
+( VGA region bases )
+vga_scr=0x02000000
+vga_tile=0x02004000
+vga_pal=0x02006000
+
+( host registers )
+host_ctrl=0x02008000
+host_flags=0x02008001
+host_mbox=0x02008002
+host_swled=0x02008003
+host_sseg0=0x02008004
+host_sseg1=0x02008005
+host_sseg2=0x02008006
+host_sseg3=0x02008007
+
+( ps2 registers )
+ps2_ctrl=0x02008008
+ps2_imask=0x02008009
+ps2_iflag=0x0200800a
+ps2_error=0x0200800b
+ps2_data=0x0200800c
+
+( rs232 registers )
+uart_ctrl=0x02008010
+uart_baudl=0x02008011
+uart_baudh=0x02008012
+uart_imask=0x02008013
+uart_iflag=0x02008014
+uart_data=0x02008015
+
+( timer registers )
+timer0_ctrl=0x02008018
+timer0_count_l=0x02008019
+timer0_count_m=0x0200801a
+timer0_count_h=0x0200801b
+timer1_ctrl=0x0200801c
+timer1_count_l=0x0200801d
+timer1_count_m=0x0200801e
+timer1_count_h=0x0200801f
+
+
+( ---------------------------------------------------------------------------- )
+( Interrupt service routines )
+
+
+( ISR common entry point )
+( ivec -- )
+isr:
+    dup #8 5i8 - jn isr_unknown
+    dup + dup + #32 isr_jumptable + @32 >r ;
+
+    align
+isr_jumptable:
+    isr_reset
+    isr_host
+    isr_ps2
+    isr_uart
+    isr_timer0
+    isr_timer1
+
+
+( Reset )
+( -- )
+isr_reset:
+    ( Perform device-specific reset/init )
+    call vga_reset
+    call host_reset
+    call ps2_reset
+    call uart_reset
+    call timer_reset
+
+    ( enable interrupts and start )
+    ien jmp start
+
+
+( Host controller flags )
+( -- )
+isr_host:
+    call host_int
+    ien ;
+
+
+( PS2 host interface )
+( -- )
+isr_ps2:
+    call ps2_int
+    ien ;
+
+
+( RS232 UART )
+( -- )
+isr_uart:
+    call uart_int
+    ien ;
+
+
+( Timer 0 )
+( -- )
+isr_timer0:
+    call timer0_int
+    ien ;
+
+
+( Timer 1 )
+( -- )
+isr_timer1:
+    call timer1_int
+    ien ;
+
+
+( Unknown source )
+( ivec -- )
+isr_unknown:
+    #32 host_swled !8 drop idis
+_isr_unknown_halt:
+    jmp _isr_unknown_halt
+
+
+( ---------------------------------------------------------------------------- )
+( Utility subroutines )
+
+
+( Copy block of bytes, allowing for overlap )
+( dest src count -- )
+mem_move:
+    >r swap
+    >r dup r> swap
+    >r dup r> swap
+    - ( dest-src )
+    dup jz _mem_move_none
+    jp _mem_move_back
+
+    ( Copy the block front-to-back )
+_mem_move_front_loop:
+    r@ jz _mem_move_done
+    >r dup @8 r@ !8 drop
+    #8 1i8 + r> #8 1i8 +
+    #8 1i8 r> - >r
+    jmp _mem_move_front_loop
+
+_mem_move_back:
+    ( Copy the block back-to-front )
+    r@ swap >r +
+    r> r@ +
+_mem_move_back_loop:
+    r@ jz _mem_move_done
+    #8 1i8 swap -
+    >r #8 1i8 swap -
+    dup @8 r@ !8 drop r>
+    #8 1i8 r> - >r
+    jmp _mem_move_back_loop
+
+_mem_move_none:
+    drop
+_mem_move_done:
+    r> drop drop drop ;
+
+
+( Fill a block of memory with an 8-bit value )
+( dest value count -- )
+mem_set_8:
+    >r
+_mem_set_8_loop:
+    r@ jz _mem_set_8_done
+    >r dup r> swap !8
+    >r #8 1i8 + r>
+    #8 1i8 r> - >r
+    jmp _mem_set_8_loop
+_mem_set_8_done:
+    r> drop drop drop ;
+
+
+( Fill a block of memory with a 16-bit value, little-endian )
+( dest value count -- )
+mem_set_16:
+    >r
+_mem_set_16_loop:
+    r@ jz _mem_set_16_done
+    >r dup r@ swap !8 drop
+    #8 1i8 + dup r@ lsr lsr lsr lsr lsr lsr lsr lsr swap !8 drop
+    #8 1i8 + r>
+    #8 1i8 r> - >r
+    jmp _mem_set_16_loop
+_mem_set_16_done:
+    r> drop drop drop ;
diff --git a/projects/cpu_0/asm/timers.asm b/projects/cpu_0/asm/timers.asm
new file mode 100644 (file)
index 0000000..5557878
--- /dev/null
@@ -0,0 +1,21 @@
+( Reset the timer blocks with reasonable defaults )
+( -- )
+timer_reset:
+    ( Enable timer 0 with 1s period, auto-restart )
+    ( #8 0x02i8 #32 timer0_count_h !8 drop )
+    ( #8 0xfai8 #32 timer0_count_m !8 drop )
+    ( #8 0xf0i8 #32 timer0_count_l !8 drop )
+    ( #8 0x0fi8 #32 timer0_ctrl    !8 drop )
+    ;
+
+
+( Timer 0 interrupt )
+( -- )
+timer0_int:
+    ;
+
+
+( Timer 1 interrupt )
+( -- )
+timer1_int:
+    ;
diff --git a/projects/cpu_0/asm/uart_console.asm b/projects/cpu_0/asm/uart_console.asm
new file mode 100644 (file)
index 0000000..f0895ea
--- /dev/null
@@ -0,0 +1,51 @@
+( Reset the UART with reasonable defaults )
+( -- )
+uart_reset:
+    ( 9600 baud, enable Tx/Rx )
+    #8 0x01i8 #32 uart_baudh !8 drop
+    #8 0x46i8 #32 uart_baudl !8 drop
+    ( #8 0x01i8 #32 uart_imask !8 drop )
+    #8 0x13i8 #32 uart_ctrl  !8 drop
+    ;
+
+
+( UART interrupt )
+( -- )
+uart_int:
+    ;
+
+
+( Print a byte out the UART )
+( c -- )
+uart_putc:
+    ( Wait for available space in the Tx FIFO )
+_uart_putc_wait:
+    #32 uart_iflag @8
+    #8 0x04i8 & jz _uart_putc_wait
+
+    ( Write byte to UART data register )
+    #32 uart_data !8 drop ;
+
+
+( Print an ASCIIZ string out the UART )
+( &s -- )
+uart_puts:
+_uart_puts_loop:
+    dup @8 dup jz _uart_puts_done
+    call uart_putc
+    #8 0x01i8 + jmp _uart_puts_loop
+_uart_puts_done:
+    drop drop ;
+
+
+( Print a hex byte )
+( b -- )
+uart_put_hex8:
+    dup #8 0xf0i8 & lsr lsr lsr lsr
+    #32 uart_xdigit_lut + @8 call uart_putc
+    #8 0x0fi8 &
+    #32 uart_xdigit_lut + @8 call uart_putc
+    ;
+
+
+uart_xdigit_lut: "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "a" "b" "c" "d" "e" "f"
diff --git a/projects/cpu_0/asm/vga_console.asm b/projects/cpu_0/asm/vga_console.asm
new file mode 100644 (file)
index 0000000..3111cc0
--- /dev/null
@@ -0,0 +1,59 @@
+( Initialize VGA hardware to some reasonable defaults )
+vga_reset:
+    ( Write palette to VGA controller )
+    #8 0x00i8 #32 vga_pal #8 0x00i8 + !8 drop ( black )
+    #8 0x60i8 #32 vga_pal #8 0x01i8 + !8 drop
+    #8 0x03i8 #32 vga_pal #8 0x02i8 + !8 drop
+    #8 0x01i8 #32 vga_pal #8 0x03i8 + !8 drop ( dark blue )
+    #8 0x6ci8 #32 vga_pal #8 0x04i8 + !8 drop
+    #8 0x0di8 #32 vga_pal #8 0x05i8 + !8 drop
+    #8 0x61i8 #32 vga_pal #8 0x06i8 + !8 drop
+    #8 0x6di8 #32 vga_pal #8 0x07i8 + !8 drop ( light gray )
+    #8 0x92i8 #32 vga_pal #8 0x08i8 + !8 drop ( dark gray )
+    #8 0xe0i8 #32 vga_pal #8 0x09i8 + !8 drop
+    #8 0x1ci8 #32 vga_pal #8 0x0ai8 + !8 drop
+    #8 0x13i8 #32 vga_pal #8 0x0bi8 + !8 drop ( light blue )
+    #8 0xfci8 #32 vga_pal #8 0x0ci8 + !8 drop
+    #8 0x1fi8 #32 vga_pal #8 0x0di8 + !8 drop
+    #8 0xe3i8 #32 vga_pal #8 0x0ei8 + !8 drop
+    #8 0xffi8 #32 vga_pal #8 0x0fi8 + !8 drop ( white )
+
+    ( TODO: Reload tile memory? )
+
+    ( Initialize console )
+    #8 0x00i8 #32 vga_cursor_loc !32 drop  ( Set the cursor to the beginning of the screen )
+    #8 0x3bi8 #32 vga_cursor_col !8  drop  ( Set the cursor color to light blue on dark blue )
+
+    ( Clear screen )
+    #32 vga_scr #32 0x00003b20i32 #32 4800i32 call mem_set_16
+
+    ;
+
+
+( Print a character to the VGA display )
+( c -- )
+vga_console_putc:
+    #32 vga_scr #32 vga_cursor_loc @32 + dup >r
+    !8 drop
+    #32 vga_cursor_col @8 r> #8 1i8 + !8 drop
+    #32 vga_cursor_loc dup @32 #8 0x02i8 + swap !32 drop
+    ;
+
+
+( Print an ASCIIZ string out the VGA display )
+( &s -- )
+vga_console_puts:
+_vga_console_puts_loop:
+    dup @8 dup jz _vga_console_puts_done
+    call vga_console_putc
+    #8 0x01i8 + jmp _vga_console_puts_loop
+_vga_console_puts_done:
+    drop drop ;
+
+
+( ---------------------------------------------------------------------------- )
+( RAM variables )
+
+
+vga_cursor_loc=0x01000000
+vga_cursor_col=0x01000004