z180 - initial commit

This commit is contained in:
Phillip Stevens 2020-04-17 00:08:56 +10:00
parent 810dad5322
commit efdf4a91fb
2 changed files with 714 additions and 0 deletions

281
portable/SDCC/Z180/port.c Normal file
View file

@ -0,0 +1,281 @@
/*
* Copyright (C) 2020 Phillip Stevens All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* 1 tab == 4 spaces!
*
*/
#include <stdlib.h>
#include "include/FreeRTOS.h"
#if __SDCC
#include "include/sdcc/task.h"
#elif __SCCZ80
#include "include/sccz80/task.h"
#endif
/*-----------------------------------------------------------*/
/* We require the address of the pxCurrentTCB variable, but don't want to know
any details of its type. */
/* Make unitialised in BSS for RomWBW HBIOS (to ensure above 0x8000) */
typedef void TCB_t;
extern volatile TCB_t * volatile pxCurrentTCB;
/*-----------------------------------------------------------*/
/*
* Macro to save all the general purpose registers, the save the stack pointer
* into the TCB.
*
* The first thing we do is save the flags then disable interrupts. This is to
* guard our stack against having a context switch interrupt after we have already
* pushed the registers onto the stack.
*
* The interrupts will have been disabled during the call to portSAVE_CONTEXT()
* so we need not worry about reading/writing to the stack pointer.
*/
#define configTICK_RATE_HZ (256) /* Timer configured */
#define configISR_IVT 0xFFE6 /* PRT1 address */
#ifdef __SCCZ80
#define configSETUP_TIMER_INTERRUPT() \
do{ \
asm( \
"EXTERN __CPU_CLOCK \n" \
"EXTERN RLDR1L, RLDR1H \n" \
"EXTERN TCR, TCR_TIE1, TCR_TDE1 \n" \
"ld de,_timer_isr \n" \
"ld hl,"string(configISR_IVT)" ; PRT1 address \n" \
"ld (hl),e \n" \
"inc hl \n" \
"ld (hl),d \n" \
"; we do configTICK_RATE_HZ ticks per second \n" \
"ld hl,__CPU_CLOCK/"string(configTICK_RATE_HZ)"/20-1 \n" \
"out0(RLDR1L),l \n" \
"out0(RLDR1H),h \n" \
"in0 a,(TCR) \n" \
"or TCR_TIE1|TCR_TDE1 \n" \
"out0 (TCR),a \n" \
); \
}while(0)
#define configRESET_TIMER_INTERRUPT() \
do{ \
asm( \
"EXTERN TCR, TMDR1L \n" \
"in0 a,(TCR) \n" \
"in0 a,(TMDR1L) \n" \
); \
}while(0)
#define configSTOP_TIMER_INTERRUPT() \
do{ \
asm( \
"EXTERN TCR, TCR_TIE1, TCR_TDE1 \n" \
"; disable down counting and interrupts for PRT1\n" \
"in0 a,(TCR) \n" \
"xor TCR_TIE1|TCR_TDE1 \n" \
"out0 (TCR),a \n" \
); \
}while(0)
#endif
#ifdef __SDCC
#define configSETUP_TIMER_INTERRUPT() \
do{ \
__asm \
EXTERN __CPU_CLOCK \
EXTERN RLDR1L, RLDR1H \
EXTERN TCR, TCR_TIE1, TCR_TDE1 \
; address of ISR \
ld de,_timer_isr \
ld hl,configISR_IVT ; PRT1 address \
ld (hl),e \
inc hl \
ld (hl),d \
; we do configTICK_RATE_HZ ticks per second \
ld hl,__CPU_CLOCK/configTICK_RATE_HZ/20-1 \
out0(RLDR1L),l \
out0(RLDR1H),h \
; enable down counting and interrupts for PRT1 \
in0 a,(TCR) \
or TCR_TIE1|TCR_TDE1 \
out0 (TCR),a \
__endasm; \
}while(0)
#define configRESET_TIMER_INTERRUPT() \
do{ \
__asm \
EXTERN TCR, TMDR1L \
; reset interrupt for PRT1 \
in0 a,(TCR) \
in0 a,(TMDR1L) \
__endasm; \
}while(0)
#define configSTOP_TIMER_INTERRUPT() \
do{ \
__asm \
EXTERN TCR, TCR_TIE1, TCR_TDE1 \
; disable down counting and interrupts for PRT1 \
in0 a,(TCR) \
xor TCR_TIE1|TCR_TDE1 \
out0 (TCR),a \
__endasm; \
}while(0)
#endif
/*-----------------------------------------------------------*/
/*
* Perform hardware setup to enable ticks from Timer.
*/
static void prvSetupTimerInterrupt( void ) __preserves_regs(iyh,iyl);
/*-----------------------------------------------------------*/
/*
* See header file for description.
*/
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
{
/* Place the parameter on the stack in the expected location. */
*pxTopOfStack-- = ( StackType_t ) pvParameters;
/* Place the task return address on stack. Not used */
*pxTopOfStack-- = ( StackType_t ) 0;
/* The start of the task code will be popped off the stack last, so place
it on first. */
*pxTopOfStack-- = ( StackType_t ) pxCode;
/* Now the registers. */
*pxTopOfStack-- = ( StackType_t ) 0xAFAF; /* AF */
*pxTopOfStack-- = ( StackType_t ) 0x0404; /* IF */
*pxTopOfStack-- = ( StackType_t ) 0xBCBC; /* BC */
*pxTopOfStack-- = ( StackType_t ) 0xDEDE; /* DE */
*pxTopOfStack-- = ( StackType_t ) 0xEFEF; /* HL */
*pxTopOfStack-- = ( StackType_t ) 0xFAFA; /* AF' */
*pxTopOfStack-- = ( StackType_t ) 0xCBCB; /* BC' */
*pxTopOfStack-- = ( StackType_t ) 0xEDED; /* DE' */
*pxTopOfStack-- = ( StackType_t ) 0xFEFE; /* HL' */
*pxTopOfStack-- = ( StackType_t ) 0xCEFA; /* IX */
*pxTopOfStack = ( StackType_t ) 0xADDE; /* IY */
return pxTopOfStack;
}
/*-----------------------------------------------------------*/
BaseType_t xPortStartScheduler( void ) __preserves_regs(a,b,c,d,e,iyh,iyl) __naked
{
/* Setup the relevant timer hardware to generate the tick. */
prvSetupTimerInterrupt();
/* Restore the context of the first task that is going to run. */
portRESTORE_CONTEXT();
/* Should not get here. */
return pdFALSE;
}
/*-----------------------------------------------------------*/
void vPortEndScheduler( void ) __preserves_regs(b,c,d,e,h,l,iyh,iyl)
{
/*
* It is unlikely that the Z80 port will get stopped.
* If required simply disable the tick interrupt here.
*/
configSTOP_TIMER_INTERRUPT();
}
/*-----------------------------------------------------------*/
/*
* Manual context switch. The first thing we do is save the registers so we
* can use a naked attribute. This is called by the application, so we don't have
* to check which bank is loaded.
*/
void vPortYield( void ) __preserves_regs(a,b,c,d,e,h,l,iyh,iyl) __naked
{
portSAVE_CONTEXT();
vTaskSwitchContext();
portRESTORE_CONTEXT();
}
/*-----------------------------------------------------------*/
/*
* Manual context switch callable from ISRs. The first thing we do is save
* the registers so we can use a naked attribute.
*/
void vPortYieldFromISR(void) __preserves_regs(a,b,c,d,e,h,l,iyh,iyl) __naked
void vPortYieldFromISR(void)
{
portSAVE_CONTEXT_IN_ISR();
vTaskSwitchContext();
portRESTORE_CONTEXT_IN_ISR();
}
/*-----------------------------------------------------------*/
/*
* Initialize Timer (PRT1 for YAZ180, and SCZ180 HBIOS).
*/
void prvSetupTimerInterrupt( void ) __preserves_regs(iyh,iyl)
{
configSETUP_TIMER_INTERRUPT();
}
/*-----------------------------------------------------------*/
void timer_isr(void) __preserves_regs(a,b,c,d,e,h,l,iyh,iyl) __naked
{
#if configUSE_PREEMPTION == 1
/*
* Tick ISR for preemptive scheduler. We can use a naked attribute as
* the context is saved at the start of timer_isr(). The tick
* count is incremented after the context is saved.
*
* Context switch function used by the tick. This must be identical to
* vPortYield() from the call to vTaskSwitchContext() onwards. The only
* difference from vPortYield() is the tick count is incremented as the
* call comes from the tick ISR.
*/
portSAVE_CONTEXT_IN_ISR();
configRESET_TIMER_INTERRUPT();
xTaskIncrementTick();
vTaskSwitchContext();
portRESTORE_CONTEXT_IN_ISR();
#else
/*
* Tick ISR for the cooperative scheduler. All this does is increment the
* tick count. We don't need to switch context, this can only be done by
* manual calls to taskYIELD();
*/
portSAVE_CONTEXT_IN_ISR();
configRESET_TIMER_INTERRUPT();
xTaskIncrementTick();
portRESTORE_CONTEXT_IN_ISR();
#endif
} // configUSE_PREEMPTION

View file

@ -0,0 +1,433 @@
/*
* Copyright (C) 2020 Phillip Stevens All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* 1 tab == 4 spaces!
*
* This file is NOT part of the FreeRTOS distribution.
*
*/
#ifndef PORTMACRO_H
#define PORTMACRO_H
#ifdef __cplusplus
extern "C" {
#endif
/*-----------------------------------------------------------
* Port specific definitions.
*
* The settings in this file configure FreeRTOS correctly for the
* given Z80 (Z180, Z80N) hardware and SCCZ80 or SDCC compiler.
*
* These settings should not be altered.
*-----------------------------------------------------------
*/
/* Type definitions. */
typedef uint16_t StackType_t;
typedef int8_t BaseType_t;
typedef uint8_t UBaseType_t;
#if configUSE_16_BIT_TICKS == 1
typedef uint16_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffff
#else
typedef uint32_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
#endif
/*-----------------------------------------------------------*/
/* General purpose stringify macros. */
#define string(a) __string(a)
#define __string(a) #a
/*-----------------------------------------------------------*/
/* Architecture specifics. */
#define portSTACK_GROWTH ( -1 )
#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
#define portBYTE_ALIGNMENT 1
/*-----------------------------------------------------------*/
/* Critical section management using sccz80 compiler. */
#ifdef __SCCZ80
#define portENTER_CRITICAL() \
do{ \
asm( \
"ld a,i \n" \
"di \n" \
"push af \n" \
); \
}while(0)
#define portEXIT_CRITICAL() \
do{ \
asm( \
"pop af \n" \
"; di ; unneeded \n" \
"jp PO,ASMPC+4 \n" \
"ei \n" \
); \
}while(0)
#define portDISABLE_INTERRUPTS() \
do{ \
asm( \
"di \n" \
); \
}while(0)
#define portENABLE_INTERRUPTS() \
do{ \
asm( \
"ei \n" \
); \
}while(0)
#define portNOP() \
do{ \
asm( \
"nop \n" \
); \
}while(0)
/*
* Macros to save all the registers, and save the stack pointer into the TCB.
*/
#define portSAVE_CONTEXT() \
do{ \
asm( \
"push af \n" \
"ld a,i \n" \
"di \n" \
"push af ; iff1:iff2\n" \
"push bc \n" \
"push de \n" \
"push hl \n" \
"exx \n" \
"ex af,af \n" \
"push af \n" \
"push bc \n" \
"push de \n" \
"push hl \n" \
"push ix \n" \
"push iy \n" \
"ld hl,0 \n" \
"add hl,sp \n" \
"ld de,(_pxCurrentTCB) \n"\
"ex de,hl \n" \
"ld (hl),e \n" \
"inc hl \n" \
"ld (hl),d \n" \
); \
}while(0)
#define portRESTORE_CONTEXT() \
do{ \
asm( \
"ld hl,(_pxCurrentTCB) \n" \
"ld e,(hl) \n" \
"inc hl \n" \
"ld d,(hl) \n" \
"ex de,hl \n" \
"ld sp,hl \n" \
"pop iy \n" \
"pop ix \n" \
"pop hl \n" \
"pop de \n" \
"pop bc \n" \
"pop af \n" \
"ex af,af \n" \
"exx \n" \
"pop hl \n" \
"pop de \n" \
"pop bc \n" \
"pop af ; iff1:iff2\n" \
"; di ; unneeded \n" \
"jp PO,ASMPC+4 \n" \
"ei \n" \
"pop af \n" \
"ret \n" \
); \
}while(0)
#define portSAVE_CONTEXT_IN_ISR() \
do{ \
asm( \
"PHASE "string(configISR_ORG)" \n" \
"._timer_isr_start \n" \
"push af \n" \
"ld a,0x7F \n" \
"inc a ; set PE \n" \
"push af ; iff1:iff2\n" \
"push bc \n" \
"push de \n" \
"push hl \n" \
"exx \n" \
"ex af,af \n" \
"push af \n" \
"push bc \n" \
"push de \n" \
"push hl \n" \
"push ix \n" \
"push iy \n" \
"ld hl,0 \n" \
"add hl,sp \n" \
"ld de,(_pxCurrentTCB) \n" \
"ex de,hl \n" \
"ld (hl),e \n" \
"inc hl \n" \
"ld (hl),d \n" \
); \
}while(0)
#define portRESTORE_CONTEXT_IN_ISR()\
do{ \
asm( \
"ld hl,(_pxCurrentTCB) \n" \
"ld e,(hl) \n" \
"inc hl \n" \
"ld d,(hl) \n" \
"ex de,hl \n" \
"ld sp,hl \n" \
"pop iy \n" \
"pop ix \n" \
"pop hl \n" \
"pop de \n" \
"pop bc \n" \
"pop af \n" \
"ex af,af \n" \
"exx \n" \
"pop hl \n" \
"pop de \n" \
"pop bc \n" \
"pop af ; iff1:iff2\n" \
"; di ; unneeded \n" \
"jp PO,ASMPC+4 \n" \
"ei \n" \
"pop af \n" \
"reti \n" \
"._timer_isr_end \n" \
"DEPHASE \n" \
); \
}while(0)
#endif
/*-----------------------------------------------------------*/
/* Critical section management using sdcc compiler. */
#ifdef __SDCC
#define portENTER_CRITICAL() \
do{ \
__asm \
ld a,i \
di \
push af \
__endasm; \
}while(0)
#define portEXIT_CRITICAL() \
do{ \
__asm \
pop af \
; di ; unneeded \
jp PO,ASMPC+4 \
ei \
__endasm; \
}while(0)
#define portDISABLE_INTERRUPTS() \
do{ \
__asm \
di \
__endasm; \
}while(0)
#define portENABLE_INTERRUPTS() \
do{ \
__asm \
ei \
__endasm; \
}while(0)
#define portNOP() \
do{ \
__asm \
nop \
__endasm; \
}while(0)
/*
* Macros to save all the registers, and save the stack pointer into the TCB.
*/
#define portSAVE_CONTEXT() \
do{ \
__asm \
push af \
ld a,i \
di \
push af ; iff1:iff2 \
push bc \
push de \
push hl \
exx \
ex af,af \
push af \
push bc \
push de \
push hl \
push ix \
push iy \
ld hl,0 \
add hl,sp \
ld de,(_pxCurrentTCB) \
ex de,hl \
ld (hl),e \
inc hl \
ld (hl),d \
__endasm; \
}while(0)
#define portRESTORE_CONTEXT() \
do{ \
__asm \
ld hl,(_pxCurrentTCB) \
ld e,(hl) \
inc hl \
ld d,(hl) \
ex de,hl \
ld sp,hl \
pop iy \
pop ix \
pop hl \
pop de \
pop bc \
pop af \
ex af,af \
exx \
pop hl \
pop de \
pop bc \
pop af ; iff1:iff2 \
; di ; unneeded \
jp PO,ASMPC+4 \
ei \
pop af \
ret \
__endasm; \
}while(0)
#define portSAVE_CONTEXT_IN_ISR() \
do{ \
__asm \
PHASE configISR_ORG \
_timer_isr_start: \
push af \
ld a,0x7F \
inc a ; set PE \
push af ; iff1:iff2 \
push bc \
push de \
push hl \
exx \
ex af,af \
push af \
push bc \
push de \
push hl \
push ix \
push iy \
ld hl,0 \
add hl,sp \
ld de,(_pxCurrentTCB) \
ex de,hl \
ld (hl),e \
inc hl \
ld (hl),d \
__endasm; \
}while(0)
#define portRESTORE_CONTEXT_IN_ISR()\
do{ \
__asm \
ld hl,(_pxCurrentTCB) \
ld e,(hl) \
inc hl \
ld d,(hl) \
ex de,hl \
ld sp,hl \
pop iy \
pop ix \
pop hl \
pop de \
pop bc \
pop af \
ex af,af \
exx \
pop hl \
pop de \
pop bc \
pop af ; iff1:iff2 \
; di ; unneeded \
jp PO,ASMPC+4 \
ei \
pop af \
reti \
_timer_isr_end: \
DEPHASE \
__endasm; \
}while(0)
#endif
/*-----------------------------------------------------------*/
/* Kernel utilities. */
extern void vPortYield( void );
#define portYIELD() vPortYield()
extern void vPortYieldFromISR( void );
#define portYIELD_FROM_ISR() vPortYieldFromISR()
/*-----------------------------------------------------------*/
/* Task function macros as described on the FreeRTOS.org WEB site. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
#ifdef __cplusplus
}
#endif
#endif /* PORTMACRO_H */