mirror of
https://codeberg.org/hkzlab/TK2048.git
synced 2025-12-25 23:02:15 +11:00
Import empty project
This commit is contained in:
parent
dddb278e87
commit
384d9b3fd1
15 changed files with 496 additions and 0 deletions
22
src/line_data.c
Normal file
22
src/line_data.c
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#include "utility.h"
|
||||
|
||||
const uint16_t line_offset_map[SCREEN_HEIGHT] = {
|
||||
0x0000, 0x0400, 0x0800, 0x0C00, 0x1000, 0x1400, 0x1800, 0x1C00, 0x0080, 0x0480, 0x0880, 0x0C80,
|
||||
0x1080, 0x1480, 0x1880, 0x1C80, 0x0100, 0x0500, 0x0900, 0x0D00, 0x1100, 0x1500, 0x1900, 0x1D00,
|
||||
0x0180, 0x0580, 0x0980, 0x0D80, 0x1180, 0x1580, 0x1980, 0x1D80, 0x0200, 0x0600, 0x0A00, 0x0E00,
|
||||
0x1200, 0x1600, 0x1A00, 0x1E00, 0x0280, 0x0680, 0x0A80, 0x0E80, 0x1280, 0x1680, 0x1A80, 0x1E80,
|
||||
0x0300, 0x0700, 0x0B00, 0x0F00, 0x1300, 0x1700, 0x1B00, 0x1F00, 0x0380, 0x0780, 0x0B80, 0x0F80,
|
||||
0x1380, 0x1780, 0x1B80, 0x1F80, 0x0028, 0x0428, 0x0828, 0x0C28, 0x1028, 0x1428, 0x1828, 0x1C28,
|
||||
0x00A8, 0x04A8, 0x08A8, 0x0CA8, 0x10A8, 0x14A8, 0x18A8, 0x1CA8, 0x0128, 0x0528, 0x0928, 0x0D28,
|
||||
0x1128, 0x1528, 0x1928, 0x1D28, 0x01A8, 0x05A8, 0x09A8, 0x0DA8, 0x11A8, 0x15A8, 0x19A8, 0x1DA8,
|
||||
0x0228, 0x0628, 0x0A28, 0x0E28, 0x1228, 0x1628, 0x1A28, 0x1E28, 0x02A8, 0x06A8, 0x0AA8, 0x0EA8,
|
||||
0x12A8, 0x16A8, 0x1AA8, 0x1EA8, 0x0328, 0x0728, 0x0B28, 0x0F28, 0x1328, 0x1728, 0x1B28, 0x1F28,
|
||||
0x03A8, 0x07A8, 0x0BA8, 0x0FA8, 0x13A8, 0x17A8, 0x1BA8, 0x1FA8, 0x0050, 0x0450, 0x0850, 0x0C50,
|
||||
0x1050, 0x1450, 0x1850, 0x1C50, 0x00D0, 0x04D0, 0x08D0, 0x0CD0, 0x10D0, 0x14D0, 0x18D0, 0x1CD0,
|
||||
0x0150, 0x0550, 0x0950, 0x0D50, 0x1150, 0x1550, 0x1950, 0x1D50, 0x01D0, 0x05D0, 0x09D0, 0x0DD0,
|
||||
0x11D0, 0x15D0, 0x19D0, 0x1DD0, 0x0250, 0x0650, 0x0A50, 0x0E50, 0x1250, 0x1650, 0x1A50, 0x1E50,
|
||||
0x02D0, 0x06D0, 0x0AD0, 0x0ED0, 0x12D0, 0x16D0, 0x1AD0, 0x1ED0, 0x0350, 0x0750, 0x0B50, 0x0F50,
|
||||
0x1350, 0x1750, 0x1B50, 0x1F50, 0x03D0, 0x07D0, 0x0BD0, 0x0FD0, 0x13D0, 0x17D0, 0x1BD0, 0x1FD0
|
||||
};
|
||||
9
src/line_data.h
Normal file
9
src/line_data.h
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef _LINE_DATA_HEADER_
|
||||
#define _LINE_DATA_HEADER_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "utility.h"
|
||||
|
||||
extern const uint16_t line_offset_map[SCREEN_HEIGHT];
|
||||
|
||||
#endif /* _LINE_DATA_HEADER */
|
||||
21
src/main.c
Normal file
21
src/main.c
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#include <stubs.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "utility.h"
|
||||
#include "mem_registers.h"
|
||||
#include "mem_map.h"
|
||||
|
||||
#include "monitor_subroutines.h"
|
||||
|
||||
__task int main () {
|
||||
POKE(P3_PWRDUP, 0); // Dirty the value checked by the reset vector
|
||||
PEEK(IO_ROMSEL); // Make sure the ROM is selected
|
||||
|
||||
while(1){
|
||||
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
11
src/mem_map.h
Normal file
11
src/mem_map.h
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#ifndef _MEMORY_MAP_HEADER_
|
||||
#define _MEMORY_MAP_HEADER_
|
||||
|
||||
#define DISPLAY_PAGE_SIZE 0x2000
|
||||
#define DISPLAY_PAGE_1 0x2000
|
||||
#define DISPLAY_PAGE_2 0xA000
|
||||
|
||||
|
||||
#define ROMRAM_BANK 0xC100
|
||||
|
||||
#endif /* _MEMORY_MAP_HEADER_ */
|
||||
49
src/mem_registers.h
Normal file
49
src/mem_registers.h
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
#ifndef _MEM_REGISTERS_HEADER_
|
||||
#define _MEM_REGISTERS_HEADER_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define ROM_MONITOR 0xFF61
|
||||
|
||||
#define ZP_WNDLFT 0x0020 // 0, left column of scroll window
|
||||
#define ZP_WNDWDTH 0x0021 // 40, width of scroll window
|
||||
#define ZP_WNDTOP 0x0022 // 0, top line of the scroll window
|
||||
#define ZP_WNDBTM 0x0023 // 24, bottom line of the scroll window
|
||||
|
||||
#define ZP_CH 0x0024 // Displacement from window left for the cursor
|
||||
#define ZP_CV 0x0025 // Displacement from top of screen (now window!) for the cursor
|
||||
|
||||
#define ZP_INVFLAG 0x0032 // Either 0x00 or 0x7F, set text color inversion
|
||||
#define ZP_PROMPT 0x0033 // Prompt character
|
||||
|
||||
#define ZP_RND 0x004E // Note that this is a 16bit register incremented by the RDKEY func
|
||||
|
||||
#define P3_PWRDUP_REF 0x03F3
|
||||
#define P3_PWRDUP 0x03F4 // Already-powered-up indicator. If it is set to the content of 0x03F3 XOR'd with 0xA5, the soft reset vector is considered valid
|
||||
|
||||
typedef struct {
|
||||
uint8_t kb: 5; // 0:5
|
||||
uint8_t prnt: 6;
|
||||
uint8_t tapein: 7;
|
||||
} datain;
|
||||
|
||||
#define IO_DATAOUT 0xC000 // (W) To keyboard and printer port
|
||||
#define IO_DATAIN 0xC010 // (R) Data input from keyboard (0:5), printer (6) and tape (7)
|
||||
#define IO_TAPEOUT 0xC020 // (R) Data output for tape, read from here to output bit on tape
|
||||
#define IO_SPEAKER 0xC030 // (R) Speaker toggle
|
||||
#define IO_DISPLAY_COLOR 0xC050 // (R / W) Access here to enable the colorburst
|
||||
#define IO_DISPLAY_BW 0xC051 // (R / W) Access here to disable the colorburst
|
||||
#define IO_MTA_OFF 0xC052 // (?)
|
||||
#define IO_MTA_ON 0xC053 // (?)
|
||||
#define IO_DISPLAY_PAGE1 0xC054 // (R / W) Access here to select the primary display page
|
||||
#define IO_DISPLAY_PAGE2 0xC055 // (R / W) Access here to select the secondary display page
|
||||
#define IO_MTB_OFF 0xC056 // (?)
|
||||
#define IO_MTB_ON 0xC057 // (?)
|
||||
#define IO_PRNT_STRB_LO 0xC058 // (R / W) Access LO/HI/LO or HI/LO/HI consecutively depending on the type of strobe pulse to create
|
||||
#define IO_PRNT_STRB_HI 0xC059 // (R / W)
|
||||
#define IO_ROMSEL 0xC05A // (R / W) Access here will make region C100-FFFF a ROM area
|
||||
#define IO_RAMSEL 0xC05B // (R / W) Access here will make region C100-FFFF a RAM area
|
||||
#define IO_KB_CTRL_LOW 0xC05E // (R / W) Set the CTRL line to 0, access is through DATAIN
|
||||
#define IO_KB_CTRL_HI 0xC05F // (R / W) Set the CTRL line to 1
|
||||
|
||||
#endif /* _MEM_REGISTERS_HEADER_ */
|
||||
19
src/monitor_subroutines.c
Normal file
19
src/monitor_subroutines.c
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#include "monitor_subroutines.h"
|
||||
|
||||
void sbrt_prntax(uint8_t msb, uint8_t lsb) {
|
||||
__asm(
|
||||
" jsr 0xF941\n"
|
||||
:
|
||||
: "Ka" (msb), "Kx" (lsb)
|
||||
:
|
||||
);
|
||||
}
|
||||
|
||||
void sbrt_prbl2(uint8_t count) {
|
||||
__asm(
|
||||
" jsr 0xF94A\n"
|
||||
:
|
||||
: "Kx" (count)
|
||||
:
|
||||
);
|
||||
}
|
||||
85
src/monitor_subroutines.h
Normal file
85
src/monitor_subroutines.h
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
#ifndef _MONITOR_SUBROUTINES_HEADER_
|
||||
#define _MONITOR_SUBROUTINES_HEADER_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
uint8_t key;
|
||||
uint8_t ch;
|
||||
} rdkey_res;
|
||||
|
||||
inline void sbrt_crout(void);
|
||||
inline void sbrt_crout1(void);
|
||||
void sbrt_prntax(uint8_t a, uint8_t x);
|
||||
inline void sbrt_prblnk(void);
|
||||
void sbrt_prbl2(uint8_t count);
|
||||
inline void sbrt_bell(void);
|
||||
inline rdkey_res sbrt_rdkey(void);
|
||||
|
||||
/*** ***/
|
||||
|
||||
#define COUT(a) (((void (*)(char))(0xFDED))(a))
|
||||
#define COUT1(a) (((void (*)(char))(0xFDF0))(a))
|
||||
#define COUTZ(a) (((void (*)(char))(0xFDF6))(a))
|
||||
#define PRBYTE(a) (((void (*)(uint8_t))(0xFDDA))(a))
|
||||
#define PRHEX(a) (((void (*)(uint8_t))(0xFDE3))(a))
|
||||
#define WAIT(a) (((void (*)(uint8_t))(0xFCA8))(a))
|
||||
#define BELL1() (((void (*)(uint8_t))(0xFBD9))(0x87))
|
||||
#define SETINV() (((void (*)(void))(0xFE80))())
|
||||
#define SETNORM() (((void (*)(void))(0xFE84))())
|
||||
|
||||
inline void sbrt_crout(void) {
|
||||
__asm volatile(
|
||||
" jsr 0xFD8E\n"
|
||||
:
|
||||
:
|
||||
:
|
||||
);
|
||||
}
|
||||
|
||||
inline void sbrt_crout1(void) {
|
||||
__asm volatile(
|
||||
" jsr 0xFD8B\n"
|
||||
:
|
||||
:
|
||||
:
|
||||
);
|
||||
}
|
||||
|
||||
inline void sbrt_prblnk(void) {
|
||||
__asm volatile(
|
||||
" jsr 0xF948\n"
|
||||
:
|
||||
:
|
||||
: "a", "x"
|
||||
);
|
||||
}
|
||||
|
||||
inline void sbrt_bell(void) {
|
||||
__asm volatile(
|
||||
" jsr 0xFF3A\n"
|
||||
:
|
||||
:
|
||||
: "a"
|
||||
);
|
||||
}
|
||||
|
||||
inline rdkey_res sbrt_rdkey(void) {
|
||||
rdkey_res res;
|
||||
uint8_t key;
|
||||
uint8_t ch;
|
||||
|
||||
__asm volatile(
|
||||
" jsr 0xFD0C\n"
|
||||
: "=Ka"(key), "=Ky"(ch)
|
||||
:
|
||||
: "a", "y"
|
||||
);
|
||||
|
||||
res.key = key;
|
||||
res.ch = ch;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif /* _MONITOR_SUBROUTINES_HEADER_ */
|
||||
105
src/tk2k_startup.s
Normal file
105
src/tk2k_startup.s
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
.rtmodel cstartup,"tk2k"
|
||||
.rtmodel version, "1"
|
||||
.rtmodel core, "*"
|
||||
|
||||
;; External declarations
|
||||
.section cstack
|
||||
.section heap
|
||||
.section data_init_table
|
||||
.section registers ; pseudo registers in zero page
|
||||
|
||||
.extern main, exit
|
||||
.extern _Zp, _Vsp, _Vfp
|
||||
|
||||
.pubweak __program_root_section, __program_start
|
||||
|
||||
call: .macro dest
|
||||
jsr \dest
|
||||
.endm
|
||||
|
||||
.section programStart, root
|
||||
__program_root_section:
|
||||
.word nextLine
|
||||
.byte 0x0a, 0x00 ; 10
|
||||
.byte 0x8c, 0x32, 0x30, 0x36, 0x32, 0x00 ; CALL 2062
|
||||
nextLine: .byte 0x00, 0x00 ; end of program
|
||||
|
||||
.section startup, root, noreorder
|
||||
__program_start:
|
||||
.section startup, noreorder
|
||||
jsr __low_level_init
|
||||
|
||||
;;; Initialize data sections if needed.
|
||||
.section startup, noroot, noreorder
|
||||
.pubweak __data_initialization_needed
|
||||
.extern __initialize_sections
|
||||
__data_initialization_needed:
|
||||
lda #.byte0 (.sectionStart data_init_table)
|
||||
sta zp:_Zp
|
||||
lda #.byte1 (.sectionStart data_init_table)
|
||||
sta zp:_Zp+1
|
||||
lda #.byte0 (.sectionEnd data_init_table)
|
||||
sta zp:_Zp+2
|
||||
lda #.byte1 (.sectionEnd data_init_table)
|
||||
sta zp:_Zp+3
|
||||
call __initialize_sections
|
||||
|
||||
.section startup, noroot, noreorder
|
||||
.pubweak __call_initialize_global_streams
|
||||
.extern __initialize_global_streams
|
||||
__call_initialize_global_streams:
|
||||
call __initialize_global_streams
|
||||
|
||||
;;; **** Initialize heap if needed.
|
||||
.section startup, noroot, noreorder
|
||||
.pubweak __call_heap_initialize
|
||||
.extern __heap_initialize, __default_heap
|
||||
__call_heap_initialize:
|
||||
lda #.byte0 __default_heap
|
||||
sta zp:_Zp+0
|
||||
lda #.byte1 __default_heap
|
||||
sta zp:_Zp+1
|
||||
lda #.byte0 (.sectionStart heap)
|
||||
sta zp:_Zp+2
|
||||
lda #.byte1 (.sectionStart heap)
|
||||
sta zp:_Zp+3
|
||||
lda #.byte0 (.sectionSize heap)
|
||||
sta zp:_Zp+4
|
||||
lda #.byte1 (.sectionSize heap)
|
||||
sta zp:_Zp+5
|
||||
call __heap_initialize
|
||||
|
||||
.section startup, root, noreorder
|
||||
tsx
|
||||
stx _InitialStack ; for exit()
|
||||
lda #0 ; argc = 0
|
||||
sta zp:_Zp
|
||||
sta zp:_Zp+1
|
||||
jsr main
|
||||
jmp exit
|
||||
|
||||
;;; ***************************************************************************
|
||||
;;;
|
||||
;;; __low_level_init - custom low level initialization
|
||||
;;;
|
||||
;;; This default routine just returns doing nothing. You can provide your own
|
||||
;;; routine, either in C or assembly for doing custom low leve initialization.
|
||||
;;;
|
||||
;;; ***************************************************************************
|
||||
|
||||
.section code
|
||||
.pubweak __low_level_init
|
||||
__low_level_init:
|
||||
rts
|
||||
|
||||
;;; ***************************************************************************
|
||||
;;;
|
||||
;;; Keep track of the initial stack pointer so that it can be restores to make
|
||||
;;; a return back on exit().
|
||||
;;;
|
||||
;;; ***************************************************************************
|
||||
|
||||
.section zdata, bss
|
||||
.pubweak _InitialStack
|
||||
_InitialStack:
|
||||
.space 1
|
||||
87
src/utility.c
Normal file
87
src/utility.c
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
#include "utility.h"
|
||||
|
||||
#include "mem_registers.h"
|
||||
#include "monitor_subroutines.h"
|
||||
#include "line_data.h"
|
||||
|
||||
// https://stackoverflow.com/questions/14009765/fastest-way-to-count-bits
|
||||
uint8_t bit_count(uint8_t b) {
|
||||
b = (b & 0x55) + (b >> 1 & 0x55);
|
||||
b = (b & 0x33) + (b >> 2 & 0x33);
|
||||
b = (b & 0x0f) + (b >> 4 & 0x0f);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
// Note that the horizontal values here are in group of 7 pixels
|
||||
void clear_box(uint8_t w, uint8_t h, uint8_t off_x, uint8_t off_y, uint8_t *disp_buf) {
|
||||
for(uint8_t y = off_y; y < off_y + h; y++) {
|
||||
uint16_t line_counter = line_offset_map[y];
|
||||
|
||||
for(uint8_t x = off_x; x < off_x + w; x++) {
|
||||
disp_buf[line_counter + x] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void draw_pic(uint16_t w, uint8_t h, uint8_t off_x, uint8_t off_y, const uint8_t *data, uint8_t *disp_buf) {
|
||||
uint8_t remainder = 0;
|
||||
uint8_t remainder_size = 0;
|
||||
uint8_t pic_width_bytes = w / 8 + ((w % 8) ? 1 : 0);
|
||||
uint16_t counter;
|
||||
|
||||
for(uint8_t row = 0; row < h; row++) {
|
||||
uint8_t screen_row = row + off_y;
|
||||
counter = line_offset_map[screen_row] + (off_x/7);
|
||||
|
||||
remainder = 0;
|
||||
remainder_size = 0;
|
||||
|
||||
// MSB is the color indicator
|
||||
for(uint8_t column = 0; column < pic_width_bytes; column++) {
|
||||
uint8_t pix_data = data[(pic_width_bytes * row) + column];
|
||||
uint8_t conv_data = (pix_data << remainder_size) | remainder;
|
||||
remainder_size++;
|
||||
remainder = (pix_data >> (8 - remainder_size)) & 0x7F;
|
||||
disp_buf[counter++] = conv_data & 0x7F;
|
||||
|
||||
if(remainder_size == 7) {
|
||||
disp_buf[counter++] = remainder & 0x7F;
|
||||
remainder = 0;
|
||||
remainder_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(remainder_size != 0) {
|
||||
uint8_t mask = ~((1 << remainder_size) - 1);
|
||||
disp_buf[counter] = (disp_buf[counter] & mask) | (remainder & 0x7F);
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void print_line(const char* line, uint8_t off_x, uint8_t off_y) {
|
||||
POKEZ(ZP_CV, off_y);
|
||||
|
||||
uint8_t cur_ch;
|
||||
for(cur_ch = 0; line[cur_ch]; cur_ch++) {
|
||||
SETNORM();
|
||||
POKEZ(ZP_CH, cur_ch + off_x);
|
||||
|
||||
COUT1(line[cur_ch]|0x80);
|
||||
|
||||
SETINV();
|
||||
COUT1(' '|0x80);
|
||||
|
||||
for(uint8_t snd_loop = 0x70; snd_loop; snd_loop--) PEEK(IO_SPEAKER);
|
||||
|
||||
WAIT(0xBE);
|
||||
}
|
||||
|
||||
SETNORM();
|
||||
POKEZ(ZP_CH, cur_ch + off_x);
|
||||
|
||||
COUT1(' '|0x80);
|
||||
WAIT(0xFF);
|
||||
}
|
||||
26
src/utility.h
Normal file
26
src/utility.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef _UTILITY_HEADER_
|
||||
#define _UTILITY_HEADER_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define SCREEN_HEIGHT 192
|
||||
#define SCREEN_WIDTH_BYTES 128
|
||||
#define BYTES_PER_LINE 40
|
||||
|
||||
#define PEEKZ(a) (*(volatile uint8_t* __attribute__((zpage)))(a))
|
||||
#define POKEZ(a, b) ((*(volatile uint8_t* __attribute__((zpage)))(a)) = b)
|
||||
|
||||
#define PEEK(a) (*(volatile uint8_t*)(a))
|
||||
#define POKE(a, b) ((*(volatile uint8_t*)(a)) = b)
|
||||
|
||||
#define PEEKW(a) (*(volatile uint16_t*)(a))
|
||||
#define POKEW(a, b) ((*(volatile uint16_t*)(a)) = b)
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
|
||||
|
||||
uint8_t bit_count(uint8_t b);
|
||||
void clear_box(uint8_t w, uint8_t h, uint8_t off_x, uint8_t off_y, uint8_t *disp_buf);
|
||||
void draw_pic(uint16_t w, uint8_t h, uint8_t off_x, uint8_t off_y, const uint8_t *data, uint8_t *disp_buf);
|
||||
void print_line(const char* line, uint8_t off_x, uint8_t off_y);
|
||||
|
||||
#endif /* _UTILITY_HEADER_ */
|
||||
Loading…
Add table
Add a link
Reference in a new issue